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

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
Стоимость запроса (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
Стоимость запроса (cost) = 1 - с индексом bitmap

Резюме

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

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

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

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

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

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

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

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

Выводы

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

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

Контакты

Начать дискуссию