Почему в OLAP-системах индексы не так востребованы, как в OLTP?

Ответ

В OLAP-системах классические индексы (B-tree, hash) менее эффективны из-за характера аналитических нагрузок. Основная операция — не поиск отдельных записей, а сканирование и агрегация больших объемов данных.

Ключевые причины:

  • Полнота сканирования: Аналитические запросы (например, GROUP BY, SUM по всему столбцу) часто требуют чтения всех строк. Индексы не ускоряют такие операции, а иногда даже замедляют из-за дополнительных операций ввода-вывода.
  • Колоночное хранение: Данные хранятся по столбцам. При запросе считываются только нужные столбцы, что само по себе является мощной оптимизацией, делая индексы на уровне строк избыточными.
  • Альтернативные методы оптимизации: Для фильтрации эффективнее используются:
    • Сортировка данных по первичному ключу (например, в ClickHouse).
    • Партиционирование по дате или категории.
    • Специализированные индексы, такие как скип-индексы (skip-indexes), которые хранят агрегированную информацию (min/max, Bloom filter) для блоков данных, позволяя пропускать нерелевантные блоки при сканировании.
  • Затраты на запись: Поддержка индексов значительно замедляет операции вставки и обновления (ETL/ELT), что критично для хранилищ данных.

Пример в ClickHouse: Вместо создания отдельного индекса используется сортировка по первичному ключу, которая определяет физический порядок данных на диске.

CREATE TABLE sales (
    event_date Date,
    product_id UInt32,
    revenue Decimal(10,2)
) ENGINE = MergeTree
ORDER BY (event_date, product_id); -- Ключ сортировки для эффективных диапазонных запросов

-- Запрос с фильтром по дате будет эффективен благодаря сортировке
SELECT product_id, SUM(revenue)
FROM sales
WHERE event_date BETWEEN '2023-01-01' AND '2023-01-31'
GROUP BY product_id;

Ответ 18+ 🔞

Э, слушай, вот объясняю на пальцах, почему в этих ваших OLAP-системах классические индексы — это как велосипед рыбаку в открытом море. В общем, ёпта, представь: у тебя не лавочка, где ты ищешь одну пачку сигарет, а целый склад, где надо посчитать, сколько тонн говядины за прошлый год продали. И ты стоишь с фонариком и B-деревом в руках. Ну и как, быстро посчитаешь? Правильно, нихуя.

Основные причины, почему это пиздец как неэффективно:

  • Полное сканирование — наш конёк: Аналитические запросы — это же сплошные GROUP BY да SUM по всему столбцу. Это как пытаться ускорить уборку снега лопатой с лазерным прицелом. Бесполезно! Нужен бульдозер, то есть чтение ВСЕХ строк подряд. Индексы тут только мешают, создавая овердохуища лишних операций ввода-вывода.
  • Колоночное хранение — уже оптимизация: Данные тут хранятся не строками, а столбцами. Захотел посчитать выручку — считаешь только столбец revenue, а product_name и прочую хуйню даже не трогаешь. Это само по себе такой прирост скорости, что классические индексы на уровне строк выглядят как мартышлюшка с гранатой — бесполезно и опасно.
  • Есть крутые альтернативы: Зачем тебе индекс, если можно данные отсортировать по ключу (как в ClickHouse) или напартиционировать по дате? А для фильтрации используют скип-индексы — хитрая жопа, которая для каждого блока данных хранит минимум/максимум или Bloom filter. Запрос прилетел, система смотрит на этот скип-индекс и говорит: "А этот блок данных нам нахуй не нужен, в нём искомых значений нет" — и пропускает его целиком! Волнение ебать, какая экономия!
  • Запись должна быть быстрой: В хранилищах постоянно льются тонны данных (ETL/ELT). А представь, что при каждой вставке тебе ещё и кучу индексов перестраивать. Это же пиздопроебибна по производительности! Терпения ноль ебать, пока всё закоммитится.

Пример на живом ClickHouse: Тут вместо заумных индексов просто говорят: "Сортировать вот так". И всё работает, как часы.

CREATE TABLE sales (
    event_date Date,
    product_id UInt32,
    revenue Decimal(10,2)
) ENGINE = MergeTree
ORDER BY (event_date, product_id); -- Вот тебе и "индекс". Данные на диске лежат отсортированно.

-- Запрос по диапазону дат выстреливает моментально, потому что читаются только нужные куски.
SELECT product_id, SUM(revenue)
FROM sales
WHERE event_date BETWEEN '2023-01-01' AND '2023-01-31'
GROUP BY product_id;

Короче, чувак, не ищи сложных путей. В аналитике главное — сканировать быстро и агрегировать, а не прыгать по строчкам. Для этого свои инструменты есть, проверенные и куда более адекватные.