Таблицы с первичным ключом
Таблица с первичным ключом использует новый движок хранения, разработанный Selena. Его основное преимущество заключается в поддержке обновлений данных в реальном времени при обеспечении эффективной производительности для сложных ad-hoc запросов. В аналитике бизнеса в реальном времени принятие решений может выиграть от таблиц с первичным ключом, которые используют самые новые данные для анализа результатов в реальном времени, что может снизить задержку данных в анализе данных. Однако первичный ключ не является бесплатным. При непра вильном использовании он может привести к ненужной трате ресурсов.
Поэтому в этом разделе мы покажем вам, как более эффективно использовать модель первичного ключа для достижения желаемых результатов.
Выбор индекса первичного ключа
Первичный индекс является наиболее критическим компонентом в таблице с первичным ключом. Индекс первичного ключа используется для хранения сопоставления между значениями первичного ключа и местоположениями строк данных, идентифицируемых значениями первичного ключа.
В настоящее время мы поддерживаем три типа индексов первичного ключа:
- Полностью в памяти индекс первичного ключа.
PROPERTIES (
"enable_persistent_index" = "false"
);
- Постоянный индекс первичного ключа на основе локального диска.
PROPERTIES (
"enable_persistent_index" = "true",
"persistent_index_type" = "LOCAL"
);
- Облачный нативный постоянный индекс первичного ключа.
PROPERTIES (
"enable_persistent_index" = "true",
"persistent_index_type" = "CLOUD_NATIVE"
);
Мы НЕ рекомендуем использовать индексирование в памяти, так как это может привести к значительной трате ресурсов памяти.
Если вы используете кластер Selena с общими данными (эластичный), мы рекомендуем выбрать облачный нативный постоянный первичный индекс. В отличие от постоянного первичного индекса на основе локального диска, он хранит полные данные индекса в удаленном объектном хранилище, а локальные диски служат только как кэш. По сравнению с постоянным первичным индексом на основе локального диска, его преимущества включают:
- Отсутствие зависимости от емкости локального диска.
- Отсутствие необходимости перестраивать индексы после перебалансировки сегментов данных.
Выбор первичного ключа
Первичный ключ обычно не помогает ускорить запросы. Вы можете указать столбец, отличный от первичного ключа, в качестве ключа сортировки, используя предложение ORDER BY для ускорения запросов. Поэтому при выборе первичного ключа вам нужно учитывать только уникальность во время процессов импорта и обновления данных.
Чем больше первичный ключ, тем больше памяти, I/O и других ресурсов он потребляет. Поэтому обычно рекомендуется избегать выбора слишком многих или слишком больших столбцов в качестве первичного ключа. Максимальный размер первичного ключа по умолчанию составляет 128 байт, контролируемый параметром primary_key_limit_size в be.conf.
Вы можете увеличить primary_key_limit_size для выбора большего первичного ключа, но имейте в виду, что это приведет к более высокому потреблению ресурсов.
Сколько места для хранения и памяти займет постоянный индекс?
Формула для расчета стоимости места хранения
(размер ключа + 8 байт) * количество строк * 50%
50% - это оценочная эффективность сжатия, фактический эффект сжатия зависит от самих данных.
Формула для расчета стоимости памяти
min(l0_max_mem_usage * количество tablet, update_memory_limit_percent * память процесса BE);
Использование памяти
Память, используемая таблицей с первичным ключом, может отслеживаться с помощью mem_tracker:
//Просмотр общей статистики памяти
http://be_ip:be_http_port/mem_tracker
// Просмотр статистики памяти таблицы с первичным ключом
http://be_ip:be_http_port/mem_tracker?type=update
// Просмотр статистики памяти таблицы с первичным ключом с более подробной информацией
http://be_ip:be_http_port/mem_tracker?type=update&upper_level=4
Элемент update в mem_tracker записывает всю память, используемую таблицей с первичным ключом, такую как индекс первичного ключа, Delete Vector и так далее.
Вы также можете отслеживать этот элемент update через службу мониторинга метрик. Например, в Grafana вы можете проверить элемент update через (элемент в красной рамке):

Подробнее о мониторинге и оповещениях с Prometheus и Grafana: https://docs.starrocks.io/docs/administration/management/monitoring/Monitor_and_Alert/
Если вы чувствительны к использованию памяти и хотите уменьшить потребление памяти во время процесса импорта таблицы PK, вы можете достичь этого через следующую конфигурацию:
be.conf
l0_max_mem_usage = (н екоторое значение меньше 104857600, по умолчанию 104857600)
skip_pk_preload = true
// Кластер без общих ресурсов
transaction_apply_worker_count = (некоторое значение меньше количества ядер процессора, по умолчанию количество ядер процессора)
// Кластер с общими данными
transaction_publish_version_worker_count = (некоторое значение меньше количества ядер процессора, по умолчанию количество ядер процессора)
l0_max_mem_usage контролирует максимальное использование памяти постоянного индекса первичного ключа на tablet. transaction_apply_worker_count и transaction_publish_version_worker_count оба контролируют максимальное количество потоков, которые могут использоваться для обработки upsert и delete в таблице с первичным ключом.
Но вам нужно помнить, что уменьшение l0_max_mem_usage может увеличить нагрузку на I/O, в то время как уменьшение transaction_apply_worker_count или transaction_publish_version_worker_count может замедлить прием данных.
Компромисс между ресурсами Compaction, свежестью данных и задержкой запросов
По сравнению с таблицами в других моделях, таблицы с первичным ключом требуют дополнительных операций для поиска по индексу первичного ключа и генерации Delete Vector во время импорта, обновления и удаления данных, что вводит дополнительные накладные расходы на ресурсы. Поэтому вам нужно найти компромисс между этими тремя факторами:
- Ограничение ресурсов Compaction.
- Свежесть данных
- Задержка запросов
Свежесть данных и задержка запросов
Если вы хотите получить лучшую свежесть данных, а также лучшую задержку запросов, это означает, что вы будете вводить высокочастотные записи, а также хотите убедиться, что они могут быть скомпактированы как можно скорее. Тогда вам понадобится больше ресурсов Compaction для обработки этих записей:
// shared-data
be.conf
compact_threads = 4
// shared-nothing
be.conf
update_compaction_num_threads_per_disk = 1
update_compaction_per_tablet_min_interval_seconds = 120
Вы можете увеличить compact_threads и update_compaction_num_threads_per_disk, или уменьшить update_compaction_per_tablet_min_interval_seconds, чтобы ввести больше ресурсов Compaction для обработки высокочастотных записей.
Как узнать, могут ли текущие ресурсы Compaction и настройки справиться с текущими высокочастотными записями? Вы можете наблюдать это следующими способами:
- Для кластера с общими данными, если Compaction не может поспевать за скоростью приема, это может привести к замедлению приема или даже ошибкам сбоя записи и остановке приема.
a. Замедление приема.
Вы можете использовать
show proc /transactions/{db_name}/running';для проверки текущих выполняющихся транзакций, и если есть какое-либо сообщение о замедлении, например:
Partition's compaction score is larger than 100.0, delay commit for xxxms. You can try to increase compaction concurrency
появляется в поле ErrMsg, это означает, что происходит замедление приема. Например:
mysql> show proc '/transactions/test_pri_load_c/running';
+---------------+----------------------------------------------+------------------+-------------------+--------------------+---------------------+------------+-------------+------------+----------------------------------------------------------------------------------------------------------------------------+--------------------+------------+-----------+--------+
| TransactionId | Label | Coordinator | TransactionStatus | LoadJobSourceType | PrepareTime | CommitTime | PublishTime | FinishTime | Reason | ErrorReplicasCount | ListenerId | TimeoutMs | ErrMsg |
+---------------+----------------------------------------------+------------------+-------------------+--------------------+---------------------+------------+-------------+------------+----------------------------------------------------------------------------------------------------------------------------+--------------------+------------+-----------+--------+
| 1034 | stream_load_d2753fbaa0b343acadd5f13de92d44c1 | FE: 172.26.94.39 | PREPARE | FRONTEND_STREAMING | 2024-10-24 13:05:01 | NULL | NULL | NULL | Partition's compaction score is larger than 100.0, delay commit for 6513ms. You can try to increase compaction concurrency, | 0 | 11054 | 86400000 | |
+---------------+----------------------------------------------+------------------+-------------------+--------------------+---------------------+------------+-------------+------------+----------------------------------------------------------------------------------------------------------------------------+--------------------+------------+-----------+--------+
b. Остановка приема. Если есть ошибка приема, например:
Failed to load data into partition xxx, because of too large compaction score, current/limit: xxx/xxx. You can reduce the loading job concurrency, or increase compaction concurrency
Это означает, что прием остановлен, потому что Compaction не может поспевать за текущими высокочастотными записями.
- Для кластера без общих ресурсов нет стратегии замедления приема, если Compaction не может поспевать за текущими высокочастотными записями. Прием завершится неудачей и вернет сообщение об о шибке:
Failed to load data into tablet xxx, because of too many versions, current/limit: xxx/xxx. You can reduce the loading job concurrency, or increase loading data batch size. If you are loading data with Routine Load, you can increase FE configs routine_load_task_consume_second and max_routine_load_batch_size.
Свежесть данных и ограничение ресурсов Compaction
Если у вас ограниченные ресурсы Compaction, но вам все еще нужно поддерживать достаточную свежесть данных, это означает, что вам нужно пожертвовать некоторой задержкой запросов.
Вы можете внести эти изменения в конфигурацию для достижения этого:
- Кластер с общими данными
fe.conf
lake_ingest_slowdown_threshold = xxx (по умолчанию 100, вы можете увеличить)
lake_compaction_score_upper_bound = xxx (по умолчанию 2000, вы можете увеличить)
Параметр lake_ingest_slowdown_threshold контролирует порог для запуска замедления приема. Когда оценка Compaction раздела превышает этот порог, система начнет замедлять прием данных. Аналогично, lake_compaction_score_upper_bound определяет порог для запуска остановки приема.
- Кластер без общих ресурсов
be.conf
tablet_max_versions = xxx (по умолча нию 1000, вы можете увеличить)
tablet_max_versions определяет порог для запуска остановки приема.
Увеличивая эти конфигурации, система может вместить больше небольших файлов данных и уменьшить частоту Compaction, но это также повлияет на задержку запросов.
Задержка запросов и ограничение ресурсов Compaction
Если вы хотите достичь хорошей задержки запросов с ограниченными ресурсами Compaction, вам нужно уменьшить частоту записи и создавать большие пакеты данных для приема.
Для конкретной реализации, пожалуйста, обратитесь к разделам о различных методах приема, которые подробно описывают, как уменьшить частоту приема и увеличить размер пакета.