Oracle database
July 6

Bitmap индекс в Oracle — когда ускоряет, а когда мешает

Введение

Битовые индексы — мощный инструмент в Oracle, но работают не везде. В этом посте — просто и по делу: когда их использовать, а когда лучше обойти стороной.

Что такое битовый индекс?

В отличие от классического B-tree индекса, который хранит ссылки на строки с конкретными значениями, битовый индекс использует битовые карты: для каждого уникального значения создаётся "битовая маска", где каждая строка таблицы — это позиция (бит). Один бит = одна строка.

Такой подход суперэффективен, когда:

  1. значений немного (низкая кардинальность)
  2. частые фильтры или группировки по этому полю.

Когда он полезен?

Посмотрим на таблицу `demo_customers`.

-- Таблица customers
CREATE TABLE demo_customers (
  customer_id   NUMBER PRIMARY KEY,
  name          VARCHAR2(100),
  region        VARCHAR2(50),
  created_at    DATE DEFAULT SYSDATE,
  created_by    NUMBER,
  modified_at   DATE,
  modified_by   NUMBER,
  is_active     CHAR(1) DEFAULT 'Y' CHECK (is_active IN ('Y', 'N')),
  deleted_at    DATE,
  deleted_by    NUMBER
);

Есть поле `is_active`, которое может быть `'Y'` или `'N'`.

Угадаете, сколько уникальных значений? Правильно — два.

Создаем индекс:

CREATE BITMAP INDEX idx_cust_is_active ON demo_customers(is_active);

Теперь запросы вроде:

SELECT COUNT(*) FROM demo_customers WHERE is_active = 'Y';

будут отрабатывать быстрее — особенно на больших таблицах.

Аналогично, если вы часто строите отчёты по `region`, и количество регионов ограничено (например, 10–20), создаём:

CREATE BITMAP INDEX idx_orders_region   ON demo_orders(region);

Это даст буст производительности при таких запросах:

SELECT region, COUNT(*)
	FROM demo_orders
 WHERE is_active = 'Y'
 GROUP BY region;

Заметьте: Oracle может эффективно объединять несколько битовых индексов в одном запросе — это ещё один плюс.

Когда НЕ стоит использовать битовые индексы?

Вот где начинаются подводные камни:

  1. Частые DML-операции (INSERT/UPDATE/DELETE): битовый индекс тяжеловат на обновления. Любое изменение строки может затронуть много битов — и Oracle будет блокировать больше, чем хотелось бы.
  2. Высокая кардинальность — например, индекс на customer_id или product_id точно не стоит делать битовым: для каждого значения будет почти свой отдельный бит, и индекс станет больше самой таблицы.
  3. В многопользовательской среде с конкурентной записью — возможны блокировки.

Допустим, вы обновляете тысячи строк в demo_orders:

UPDATE demo_orders
   SET is_active = 'N'
 WHERE order_date < ADD_MONTHS(SYSDATE, -12);

Битовый индекс is_active здесь будет тормозить: Oracle должен будет перестраивать множество битов, возможно с блокировками. В OLTP-сценариях лучше использовать обычный B-tree или вообще обойтись без индекса.

Проверяем скорость с и без индекса

-- включаем простую метрику времени
SET timing ON

-- 1. Без индекса
DROP INDEX idx_cust_is_active;
SELECT /*+ gather_plan_statistics */ COUNT(*)
FROM demo_customers
WHERE is_active = 'Y';
SELECT * FROM TABLE(dbms_xplan.display_cursor(NULL,NULL,'ALLSTATS LAST'));

Стоимость запроса (cost) = 5 - без индекса bitmap

-- 2. С индексом
CREATE BITMAP INDEX idx_cust_is_active
  ON demo_customers(is_active);
SELECT /*+ gather_plan_statistics */ COUNT(*)
  FROM demo_customers
 WHERE is_active = 'Y';
SELECT * FROM TABLE(dbms_xplan.display_cursor(NULL,NULL,'ALLSTATS LAST'));

Стоимость запроса (cost) = 1 - с индексом bitmap

Резюме

Используй битовый индекс, если:

  1. Поле с низкой кардинальностью (`Y/N`, фиксированный список значений)
  2. Часто идёт фильтрация, группировка, аналитика
  3. Таблица читается чаще, чем изменяется

Избегай, если:

  1. Поле с уникальными или почти уникальными значениями
  2. Частые INSERT/UPDATE/DELETE
  3. Сценарии с высокой конкурентностью

Полезные ссылки

  1. Индексы в Oracle (перейти)
  2. Bitmap индекс в Oracle (перейти)

Файлы и скрипты

Исходные файлы можно найти в (GIT).

Выводы

Битовый индекс — отличный инструмент, но не волшебная палочка. Бери и применяй — но не везде!

P.S. Если что-то не работает или нужен архив в другом формате — напишите мне.

Контакты

Написать автору | Telegram Сайт автора