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

Таблицы с первичным ключом

Таблица с первичным ключом использует новый движок хранения, разработанный Selena. Его основное преимущество заключается в поддержке обновлений данных в реальном времени при обеспечении эффективной производительности для сложных ad-hoc запросов. В аналитике бизнеса в реальном времени принятие решений может выиграть от таблиц с первичным ключом, которые используют самые новые данные для анализа результатов в реальном времени, что может снизить задержку данных в анализе данных. Однако первичный ключ не является бесплатным. При неправильном использовании он может привести к ненужной трате ресурсов.

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

Выбор индекса первичного ключа

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

В настоящее время мы поддерживаем три типа индексов первичного ключа:

  1. Полностью в памяти индекс первичного ключа.
PROPERTIES (
"enable_persistent_index" = "false"
);
  1. Постоянный индекс первичного ключа на основе локального диска.
PROPERTIES (
"enable_persistent_index" = "true",
"persistent_index_type" = "LOCAL"
);
  1. Облачный нативный постоянный индекс первичного ключа.
PROPERTIES (
"enable_persistent_index" = "true",
"persistent_index_type" = "CLOUD_NATIVE"
);

Мы НЕ рекомендуем использовать индексирование в памяти, так как это может привести к значительной трате ресурсов памяти.

Если вы используете кластер Selena с общими данными (эластичный), мы рекомендуем выбрать облачный нативный постоянный первичный индекс. В отличие от постоянного первичного индекса на основе локального диска, он хранит полные данные индекса в удаленном объектном хранилище, а локальные диски служат только как кэш. По сравнению с постоянным первичным индексом на основе локального диска, его преимущества включают:

  1. Отсутствие зависимости от емкости локального диска.
  2. Отсутствие необходимости перестраивать индексы после перебалансировки сегментов данных.

Выбор первичного ключа

Первичный ключ обычно не помогает ускорить запросы. Вы можете указать столбец, отличный от первичного ключа, в качестве ключа сортировки, используя предложение 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 через (элемент в красной рамке):

grafana

Подробнее о мониторинге и оповещениях с 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 и настройки справиться с текущими высокочастотными записями? Вы можете наблюдать это следующими способами:

  1. Для кластера с общими данными, если 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 не может поспевать за текущими высокочастотными записями.

  1. Для кластера без общих ресурсов нет стратегии замедления приема, если 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, вам нужно уменьшить частоту записи и создавать большие пакеты данных для приема.

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