Что в OLAP бд используется вместо индексов для оптимизации поиска?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что в OLAP БД используется вместо индексов для оптимизации поиска?
В OLAP (Online Analytical Processing) базах данных используются совершенно другие подходы к оптимизации поиска, чем в традиционных OLTP системах. Вместо индексов применяются специализированные техники, оптимизированные для аналитических запросов с полными сканированиями больших объёмов данных.
1. Agregation (Агрегация и предвычисление)
Это основной метод оптимизации в OLAP.
Вместо индексов OLAP БД используют предвычисленные агрегации (fact tables с различными уровнями гранулярности).
-- Исходная детальная таблица (fact table)
CREATE TABLE sales_detail (
transaction_id INT,
product_id INT,
customer_id INT,
store_id INT,
date_id INT,
amount DECIMAL(10, 2)
);
-- Размер: 10 миллиардов строк, 1 TB
-- Предвычисленная агрегация по дням
CREATE TABLE sales_by_day (
date_id INT,
product_id INT,
store_id INT,
total_sales DECIMAL(12, 2),
transaction_count INT
);
-- Размер: 1 миллион строк, 100 MB
-- Вместо сканирования 1 TB для ответа на запрос:
-- SELECT SUM(amount) FROM sales_detail WHERE date_id = 20240101
-- Просто скорее сканируем 100 MB агрегированной таблицы!
SELECT SUM(total_sales) FROM sales_by_day WHERE date_id = 20240101;
2. Column-oriented Storage (Колончатое хранилище)
Основное отличие OLAP от OLTP.
Данные хранятся по колонкам, а не по строкам. Это позволяет:
- Читать только необходимые колонки
- Лучше компрессировать данные (одинаковые значения в колонке сжимаются эффективнее)
- Параллелизировать обработку
ОЛТП (Row-oriented):
Transaction 1: [ID=1, Name=John, Age=30, Salary=50000, Dept=Sales, ...]
Transaction 2: [ID=2, Name=Jane, Age=28, Salary=55000, Dept=Engineering, ...]
Все данные строки в одном месте памяти
ОЛАП (Column-oriented):
ID Column: [1, 2, 3, 4, 5, ...]
Name Column: [John, Jane, Bob, ...]
Age Column: [30, 28, 35, ...]
Salary Column: [50000, 55000, 60000, ...]
Для запроса SELECT AVG(Age) — читаем ТОЛЬКО Age колонку!
Примеры OLAP БД с column-oriented хранилищем:
- ClickHouse — на 100% column-oriented
- Parquet формат — для column-oriented данных
- Apache Cassandra — можно настроить
3. Compression (Сжатие данных)
ОЛАП базы используют специализированные алгоритмы сжатия, которые работают лучше на column-oriented данных:
Оригинальные данные (Age column):
[30, 30, 30, 28, 28, 35, 35, 35, 35, ...]
RLE (Run-Length Encoding):
(30, 3 раза), (28, 2 раза), (35, 4 раза) — 10x сжатие!
Dictionary encoding для String колонок:
Depт values: ['Sales', 'Engineering', 'Marketing']
Храним: [0, 0, 1, 1, 2, ...] вместо строк
Результат: 1 TB данных → 50-100 GB после сжатия
4. Partitioning (Партиционирование)
Данные разделяются на меньшие части по ключевым колонкам (usually time-based).
-- Партиционирование по дате
CREATE TABLE sales (
transaction_id INT,
product_id INT,
amount DECIMAL,
date DATE
)
PARTITION BY RANGE (YEAR(date)) (
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025)
);
-- Запрос по 2024 году сканирует только partition p2024!
SELECT * FROM sales WHERE date >= '2024-01-01' AND date < '2025-01-01';
-- Сканирование: 100 GB вместо 1 TB = 10x ускорение
5. Bitmap Indexes (Битовые индексы)
Вместо B-tree индексов, используются битовые карты для низкокардинальных колонок (мало уникальных значений).
Традиционный индекс (B-tree):
Department: [Sales] → [1, 5, 7, 23, 45, ...]
[Engineering] → [2, 4, 8, 15, ...]
[Marketing] → [3, 6, 9, ...]
Bitmap Index:
Sales: [1, 0, 0, 1, 0, 0, 0, 1, ...] (16 GB vs 1 GB!)
Engineering: [0, 1, 0, 0, 1, 0, 0, 0, ...]
Marketing: [0, 0, 1, 0, 0, 1, 0, 0, ...]
Для запроса: SELECT COUNT(*) FROM employees WHERE department IN ('Sales', 'Engineering')
Просто OR'им два bitmap'а!
6. Metadata и Statistics
ОЛАП БД хранят богатую статистику для оптимизации плана запроса:
Для каждого partition/segment:
- Min/Max values (для pruning)
- Row count
- Distinct value count (cardinality)
- Null count
Примеры:
Partition 2024-01-01:
product_id: min=1, max=500, count_distinct=450
amount: min=0.50, max=9999.99
Запрос: SELECT COUNT(*) FROM sales WHERE product_id = 1001
Оптимизатор сразу видит: product_id max = 500, значит partition не содержит 1001
Партиция полностью пропускается (partition pruning)!
7. Материализованные представления (Materialized Views)
Предвычисленные результаты популярных запросов.
CREATE MATERIALIZED VIEW sales_by_category_and_date AS
SELECT
category_id,
DATE(order_date) as date,
SUM(amount) as total_sales,
COUNT(*) as orders
FROM orders
GROUP BY category_id, DATE(order_date);
-- При запросе этого вида, БД использует materialized view
-- вместо пересчёта всех данных!
SELECT * FROM sales_by_category_and_date WHERE date = '2024-01-01';
8. Projection (Проекции)
В некоторых OLAP БД (Vertica, Greenplum) используются проекции — альтернативные представления данных оптимизированные для конкретных запросов.
Основная таблица: sales(transaction_id, product_id, customer_id, amount, date)
Проекция 1 (для запросов по дате):
Ордер: [date, product_id, amount]
Компрессия: RLE по date
Проекция 2 (для запросов по customer):
Ордер: [customer_id, date, amount]
Запрос SELECT SUM(amount) FROM sales WHERE date = '2024-01-01'
Использует Проекцию 1 — намного быстрее!
Сравнение: OLTP vs OLAP
| Аспект | OLTP (SQL) | OLAP (DW) |
|---|---|---|
| Хранение | Row-oriented | Column-oriented |
| Индексы | B-tree, Hash | Bitmap, минимальные |
| Оптимизация | Для single rows | Для агрегаций |
| Сжатие | Минимальное | Максимальное (10x) |
| Партиции | Опционально | Обязательно |
| Агрегации | On-the-fly | Предвычислены |
| Обновления | Частые | Редкие (batch) |
| Запросы | Мало данных, быстро | Много данных, медленнее |
| Примеры | PostgreSQL, MySQL | Snowflake, BigQuery, ClickHouse |
Практический пример: ClickHouse
-- Column-oriented, с автоматическим partition pruning
CREATE TABLE events (
timestamp DateTime,
user_id UInt32,
event_type String,
properties String
)
ENGINE = MergeTree()
ORDER BY (timestamp, user_id)
PARTITION BY toDate(timestamp);
-- Вставляем 1 миллиард событий
INSERT INTO events SELECT ...
-- Запрос сканирует только partition за 2024-01-01
SELECT
event_type,
COUNT(*) as count
FROM events
WHERE timestamp >= '2024-01-01' AND timestamp < '2024-01-02'
GROUP BY event_type;
-- Время выполнения: < 100 ms вместо минут на традиционной БД
Когда использовать OLAP техники
✅ OLAP (column-oriented, агрегации):
- Аналитические запросы (SUM, AVG, COUNT)
- Полное сканирование больших таблиц
- Данные, обновляемые batch'ами (раз в день/час)
- Экспад/Snowflake/BigQuery/ClickHouse
❌ OLTP (row-oriented, индексы):
- CRUD операции на single rows
- Частые обновления
- Транзакции (ACID)
- PostgreSQL/MySQL/Oracle
Вывод
Вместо индексов OLAP БД используют:**
- Партиционирование — исключают ненужные данные
- Агрегацию — предвычисляют результаты
- Column-oriented хранилище — читают только нужные колонки
- Сжатие — уменьшают объём данных в памяти
- Bitmap индексы — для низкокардинальных колонок
- Statistics — для умного pruning
Это позволяет обрабатывать петабайты данных за считанные секунды вместо минут/часов на традиционных системах с индексами.