Перейти к содержимому
Последнее обновление

Как провести POC для Apache Doris

В этом документе собраны частые вопросы новых пользователей, которые помогут быстрее провести POC. Материал организован в соответствии с типичным порядком работы над POC:

  1. Проектирование таблиц — выбор модели данных, ключа сортировки, стратегии партиционирования и распределения по бакетам.
  2. Загрузка данных — выбор подходящего способа загрузки и предотвращение распространённых проблем.
  3. Оптимизация запросов — диагностика медленных запросов и настройка бакетов и индексов.
  4. Запросы к озеру данных — дополнительные рекомендации по оптимизации для сценариев Lakehouse.
Краткий список проверок

Выполните базовую проверку за 5 минут:

  1. Используется ли в таблице подходящая модель данных (Duplicate/Unique/Aggregate Key)?
  2. Кратно ли количество бакетов количеству BE?
  3. Содержат ли запросы по времени столбец партиционирования?
  4. Включён ли Data Cache (для запросов к озеру данных)?

Проектирование таблиц​

При создании таблицы в Doris нужно принять четыре решения, которые влияют на производительность загрузки и запросов: выбрать модель данных, ключ сортировки, партиционирование и распределение по бакетам.

Модель данных​

Выбирайте модель с учётом того, как записываются данные:

Характер данныхРекомендуемая модельПричина
Только добавление данных (логи, события, таблицы фактов)Duplicate Key (по умолчанию)Сохраняет все строки; обеспечивает наилучшую производительность запросов
Обновление по первичному ключу (CDC, Upsert)Unique KeyНовые строки заменяют старые строки с тем же ключом
Предварительно агрегированные метрики (PV, UV, сводные данные)Aggregate KeyОбъединяет строки с помощью SUM/MAX/MIN при записи

Duplicate Key подходит для большинства сценариев. Подробнее см. в разделе Обзор моделей данных.

Ключ сортировки​

Doris строит префиксный индекс по первым 36 байтам ключа сортировки. При настройке ключа сортировки придерживайтесь следующих принципов:

  • Сначала размещайте столбцы, по которым чаще всего фильтруют данные: в начале должны находиться столбцы, которые чаще всего используются в условиях WHERE.
  • Сначала размещайте типы фиксированной длины: располагайте типы фиксированной длины, такие как INT, BIGINT и DATE, перед VARCHAR, поскольку префиксный индекс обрывается сразу при встрече с VARCHAR.
  • Дополняйте ключ сортировки инвертированными индексами: для столбцов, которые не охватывает префиксный индекс, добавьте инвертированный индекс, чтобы ускорить фильтрацию.

Партиционирование​

Если в данных есть столбец времени, используйте AUTO PARTITION BY RANGE(date_trunc(time_col, 'day')), чтобы включить отсечение партиций. Doris автоматически пропускает ненужные партиции.

Распределение по бакетам​

По умолчанию используется распределение по бакетам Random (рекомендуется для таблиц Duplicate Key). Если вы часто фильтруете данные или выполняете JOIN по определённому столбцу, используйте DISTRIBUTED BY HASH(that_column). Подробнее см. в разделе Распределение данных по бакетам.

Как выбрать количество бакетов:

ПринципОписание
Количество бакетов должно быть кратно количеству BEОбеспечивает равномерное распределение данных. При последующем добавлении BE запросы обычно затрагивают несколько партиций, поэтому производительность не страдает
Как можно меньшеПозволяет избежать создания небольших файлов
Объём сжатых данных в каждом бакете <= 20 GB<= 10 GB для таблиц Unique Key. Проверяйте с помощью SHOW TABLETS FROM your_table
Не более 128 бакетов на партициюЕсли нужно больше, сначала увеличьте количество партиций. Предельное значение — 1024, но в производственных средах оно требуется редко

Шаблоны создания таблиц​

Аналитика логов и событий​

Сценарий использования: Данные, которые только добавляются, например логи, события и показания датчиков.

Предварительные условия: Особых требований нет.

CREATE TABLE app_logs
(
log_time DATETIME NOT NULL,
log_level VARCHAR(10),
service_name VARCHAR(50),
trace_id VARCHAR(64),
message STRING,
INDEX idx_message (message) USING INVERTED PROPERTIES("parser" = "unicode")
)
AUTO PARTITION BY RANGE(date_trunc(`log_time`, 'day'))
()
DISTRIBUTED BY RANDOM BUCKETS 10;

Порядок проверки:

-- 1. Verify that partitions are created automatically
SHOW PARTITIONS FROM app_logs;

-- 2. Verify that data is evenly distributed
SHOW TABLETS FROM app_logs;

Панели мониторинга в реальном времени и Upsert (CDC)​

Сценарий использования: Данные, которые требуется обновлять по первичному ключу, например профили пользователей и записи заказов.

Предварительные условия: Явно определённый столбец первичного ключа.

CREATE TABLE user_profiles
(
user_id BIGINT NOT NULL,
username VARCHAR(50),
email VARCHAR(100),
status TINYINT,
updated_at DATETIME
)
UNIQUE KEY(user_id)
DISTRIBUTED BY HASH(user_id) BUCKETS 10;

Порядок проверки:

-- 1. Verify primary key uniqueness (only one latest row per user_id)
SELECT user_id, count(*) as cnt FROM user_profiles GROUP BY user_id HAVING cnt > 1;

-- 2. Verify data distribution
SHOW TABLETS FROM user_profiles;

Агрегация метрик​

Сценарий использования: Данные, для которых требуется предварительная агрегация, например статистика посещаемости и бизнес-отчёты.

Предварительные условия: Явно определённые столбцы измерений для агрегации и столбцы метрик.

CREATE TABLE site_metrics
(
dt DATE NOT NULL,
site_id INT NOT NULL,
pv BIGINT SUM DEFAULT '0',
uv BIGINT MAX DEFAULT '0'
)
AGGREGATE KEY(dt, site_id)
AUTO PARTITION BY RANGE(date_trunc(`dt`, 'day'))
()
DISTRIBUTED BY HASH(site_id) BUCKETS 10;

Порядок проверки:

-- 1. Verify that aggregation works (metrics with the same dt+site_id are merged)
SELECT dt, site_id, pv, uv FROM site_metrics ORDER BY dt DESC LIMIT 10;

-- 2. Verify that partition pruning works
EXPLAIN SELECT * FROM site_metrics WHERE dt = '2024-01-01';

Загрузка данных​

Выберите подходящий способ загрузки и следуйте этим рекомендациям, чтобы избежать распространённых проблем с производительностью:

  • Не используйте INSERT INTO VALUES для массовой загрузки данных. Вместо этого используйте Stream Load или Broker Load. Подробнее см. в разделе Обзор загрузки данных.
  • Сначала объединяйте записи в пакеты на стороне клиента. Частая загрузка небольшими пакетами приводит к накоплению версий. Если объединение на стороне клиента невозможно, используйте Group Commit.
  • Разбивайте большие загрузки на небольшие пакеты. При сбое длительную загрузку приходится начинать заново. Для инкрементальной загрузки используйте INSERT INTO SELECT с S3 TVF.
  • Включите load_to_single_tablet для таблиц Duplicate Key с распределением по бакетам Random, чтобы уменьшить усиление записи.

Быстрая проверка:

-- View ingestion task status
SHOW LOAD WHERE label = 'your_label';

-- Check version pile-up (a high Version Count indicates ingestion is too frequent)
SHOW TABLETS FROM your_table;

Подробнее см. в разделе Рекомендации по загрузке данных.

Оптимизация запросов​

Распределение по бакетам​

Количество бакетов напрямую влияет на параллелизм запросов и накладные расходы на планирование, поэтому нужно найти баланс:

  • Не создавайте слишком много бакетов. Большое количество маленьких таблетов увеличивает накладные расходы на планирование и может снизить производительность запросов до 50%.
  • Не создавайте слишком мало бакетов. Недостаточное количество таблетов ограничивает параллельное использование CPU.
  • Избегайте перекоса данных. Используйте SHOW TABLETS, чтобы проверить размеры таблетов. Если размеры существенно различаются, перейдите на распределение по бакетам Random или выберите столбец распределения с более высокой кардинальностью.

Команда диагностики:

-- Check tablet size distribution (used to detect data skew)
SHOW TABLETS FROM your_table\G
-- Review the tablet count and size to decide whether to adjust the bucket count

Рекомендации по выбору количества бакетов см. в разделе Распределение по бакетам.

Индексы​

  • Правильно задавайте ключ сортировки. В отличие от таких систем, как PostgreSQL, Doris индексирует только первые 36 байт ключа сортировки, причём индекс обрывается сразу при встрече с VARCHAR. Столбцы за пределами префикса не могут использовать преимущества ключа сортировки и требуют инвертированного индекса. См. раздел Ключ сортировки.

Проверьте, что ключ сортировки работает:

EXPLAIN SELECT * FROM your_table WHERE filter_column = 'xxx';
-- Check whether the Sort Key index is used

Инструменты диагностики​

Для диагностики медленных запросов используйте Query Profile.

Быстрый старт:

-- 1. Run the query and obtain the query_id
SET enable_profile = true;
SELECT ...;

-- 2. View the Query Profile
SHOW PROFILELIST;
SHOW PROFILE WHERE query_id = 'xxx';

Запросы к озеру данных​

Если ваш POC включает запросы через Doris к данным в озере, например Hive, Iceberg или Paimon (сценарии Lakehouse), следующие факторы сильнее всего влияют на результаты тестирования.

Проверьте, что отсечение партиций работает​

Таблицы в озере данных часто содержат огромные объёмы данных, поэтому всегда включайте столбец партиционирования в условие WHERE, чтобы Doris сканировал только нужные партиции. Выполните EXPLAIN <SQL> и проверьте поле partition, чтобы убедиться, что отсечение работает:

0:VPAIMON_SCAN_NODE(88)
partition=203/0 -- 203 partitions are pruned, 0 are actually scanned

Если количество партиций значительно превышает ожидаемое, проверьте, корректно ли условие WHERE сопоставляется со столбцом партиционирования.

Включите Data Cache​

Задержка IO при обращении к удалённому хранилищу (HDFS / объектное хранилище) в несколько раз выше, чем при работе с локальными дисками. Data Cache сохраняет недавно прочитанные данные из удалённого хранилища на локальном диске BE, поэтому повторные запросы к тем же данным могут выполняться почти так же быстро, как запросы к внутренним таблицам.

  • По умолчанию кеш отключён. Инструкции по настройке см. в документации Data Cache.
  • Предварительный прогрев кеша поддерживается начиная с версии 4.0.2 и позволяет заранее загрузить часто используемые данные перед тестированием в рамках POC.
подсказка

Во время POC выполните запрос один раз, чтобы заполнить кеш, а затем используйте время выполнения второго запроса в качестве базового показателя. Это точнее отражает производительность производственной среды в установившемся режиме.

Работа с небольшими файлами​

Данные в озере часто хранятся во множестве небольших файлов. Небольшие файлы разбиваются на большое количество Splits, что увеличивает потребление памяти FE, может приводить к OOM и повышает накладные расходы на планирование запросов.

  • Устраняйте проблему на стороне источника (рекомендуется): периодически объединяйте небольшие файлы на стороне Hive/Spark, чтобы размер каждого файла превышал 128 MB.
  • Запасной вариант на стороне Doris: используйте SET max_file_split_num = 50000; (поддерживается начиная с 4.0.4), чтобы ограничить максимальное количество Splits на одно сканирование и предотвратить OOM.

Используйте Query Profile для диагностики​

Узким местом запросов к озеру данных обычно становится IO, а не вычисления. Query Profile помогает найти причину медленного выполнения запросов. Обратите внимание на следующее:

  • Количество Split и объём данных: проверьте, не сканируется ли слишком много данных.
  • Метрики MergeIO: если MergedBytes значительно превышает RequestBytes, усиление чтения велико; уменьшите merge_io_read_slice_size_bytes (по умолчанию 8 MB), чтобы снизить его.
  • Доля попаданий в кеш: убедитесь, что Data Cache работает эффективно.

Другие способы оптимизации см. в разделе Оптимизация запросов к озеру данных.

Распространённые ошибки и их решения​

Создание таблицы завершается ошибкой "Tablet count should be greater than 0"​

Причина: Количество бакетов задано равным 0 или распределение по бакетам не указано.

Решение: Проверьте, содержит ли DDL конструкцию DISTRIBUTED BY HASH(xxx) BUCKETS n, и убедитесь, что после BUCKETS указано положительное целое число.

-- Correct example
DISTRIBUTED BY HASH(user_id) BUCKETS 10;

Запрос выполняется медленно, предположительно индекс не используется​

Порядок диагностики:

  1. Выполните EXPLAIN SQL, чтобы просмотреть план запроса и проверить, используется ли индекс Sort Key.
  2. Выполните SHOW TABLETS FROM table_name, чтобы проверить, одинаковы ли размеры таблетов.
  3. Просмотрите Query Profile, чтобы найти узкое место.
-- Check whether the index is used (look at output_id for Sort Key columns)
EXPLAIN SELECT * FROM table_name WHERE key_col = 'xxx';

-- Check tablet size (to detect data skew)
SHOW TABLETS FROM table_name;

OOM при запросах к озеру данных​

Причина: Слишком большое количество небольших файлов приводит к резкому росту количества Split.

Решение:

  1. Объедините небольшие файлы на стороне источника данных (размер каждого файла > 128 MB).
  2. Ограничьте количество Split на стороне Doris:
SET max_file_split_num = 50000;

Накопление версий при загрузке замедляет запросы​

Причина: Частая загрузка небольшими пакетами создаёт слишком много версий.

Решение:

  1. Объедините пакеты загрузки и уменьшите частоту загрузок.
  2. Включите Group Commit:
SET group_commit_mode = 'async_mode';

Часто задаваемые вопросы​

Вопрос: Сколько времени занимает POC?​

Базовая проверка функциональности (создание таблиц, загрузка данных, простые запросы) обычно занимает 1-2 дня. На детальную настройку производительности требуется 3-5 дней.

Вопрос: Как выбрать количество бакетов при создании таблицы?​

Сначала задайте количество бакетов, кратное количеству узлов BE, чтобы обеспечить равномерное распределение данных. Объём сжатых данных в каждом бакете должен быть <= 20 GB (<= 10 GB для таблиц Unique Key).

Вопрос: Что делать, если запросы выполняются медленнее, чем ожидалось?​

  1. Выполните EXPLAIN, чтобы проверить, используется ли индекс.
  2. Выполните SHOW TABLETS, чтобы проверить наличие перекоса данных.
  3. Просмотрите Query Profile, чтобы найти узкое место.

Вопрос: Нужно ли включать Data Cache?​

Если ваша нагрузка включает запросы к озеру данных (Hive/Iceberg/Paimon), включите его. Первый запрос автоматически кеширует данные, а повторные запросы по производительности приближаются к запросам к внутренним таблицам.

На этой странице