Перед началом работы
nyc_taxi.trips_small_inferred. Создайте и загрузите её, если ещё этого не сделали:
Настройка демонстрационного набора данных
Настройка демонстрационного набора данных
Размер исходного файла Parquet составляет примерно 5,8 ГБ. Его загрузка может занять несколько минут в зависимости от скорости сети и доступных ресурсов.
Обзор процесса
- Выполните три независимых запроса рабочей нагрузки к выведенной схеме, чтобы определить базовый уровень.
- Создайте таблицу с более точными типами столбцов, загрузите те же данные и повторно выполните запросы.
- Создайте ещё одну таблицу с той же оптимизированной схемой и ключом сортировки, затем снова выполните запросы.
Задайте базовую рабочую нагрузку
Эти настройки позволяют обеспечить сопоставимость повторных запусков при тестировании. После завершения измерений восстановите прежние значения.
system.query_log, см. в разделе Создание воспроизводимой базовой линии.
Фильтрация по вычисленной скорости поездки
Агрегация поездок за период
Фильтрация по числу пассажиров
Все три запроса считывают примерно 329 млн строк — почти столько же, сколько строк в таблице. Это позволяет оптимизировать два аспекта рабочей нагрузки: снизить затраты на обработку выбранных столбцов, а затем, когда это позволяют фильтры, сократить число выбираемых строк.
Оптимизируйте схему
Избегайте ненужных столбцов с типом Nullable
Nullable помимо значений хранит маску NULL. Используйте Nullable, когда важно различать NULL и значение типа по умолчанию, но избегайте его для столбцов, которые гарантированно содержат значение.
Подсчитайте значения NULL в столбцах, используемых в примере схемы:
ratecode_id, mta_tax и payment_type этого набора данных есть значения NULL. В оптимизированной схеме Nullable сохраняется для этих столбцов и удаляется из остальных.
Используйте LowCardinality для повторяющихся значений
LowCardinality использует кодирование с использованием словаря и позволяет сократить затраты на хранение и обработку данных в столбцах с большим количеством повторяющихся значений. Перед применением проверьте количество уникальных значений:
LowCardinality, хотя влияние на рабочую нагрузку всё равно следует измерить. Около 10 000 уникальных значений — полезная отправная точка для выявления кандидатов, а не фиксированный предел.
Выбирайте более точные типы данных
Int64 или Float64, проверьте минимальные и максимальные значения числовых столбцов:
UInt8, хотя passenger_count достигает максимального значения 255. В примере также используется Float32 для trip_distance и Decimal32 для денежных значений. Все значения в этом наборе данных укладываются в целевые диапазоны, а для сравнения агрегированных результатов в рабочей нагрузке примера достаточно сниженной точности с плавающей запятой и точности денежных значений до центов. Сохраняйте более широкие исходные типы, если требуются точные исходные значения. В примере выведенные столбцы DateTime64 заменяются на DateTime в том же часовом поясе UTC, поскольку запросам из примера не требуется точность до долей секунды.
Этот выбор применим только к данному набору данных. Прежде чем применять те же изменения, проверьте требования к диапазону, точности и допустимости NULL-значений для данных в продакшне.
Примените изменения схемы
nyc_taxi.trips_small_inferred на nyc_taxi.trips_small_no_pk, затем повторно выполните все три запроса. В исходном примере были получены следующие характерные результаты:
Запросы по-прежнему читают одинаковое число строк, но оптимизированная схема уменьшает объём данных, приходящийся на эти строки. Поэтому длительность запросов и пиковое потребление памяти сокращаются без изменения выборки данных.
Сравните размер двух таблиц на диске:
Оптимизация ключа сортировки
MergeTree ключ сортировки определяет, как строки располагаются на диске. ClickHouse строит по этому порядку разреженный первичный индекс, позволяющий пропускать гранулы, не соответствующие фильтрам запроса. В отличие от первичного ключа во многих транзакционных базах данных, он не обеспечивает уникальность.
Ключ сортировки должен соответствовать фильтрам, используемым в важных регулярно выполняемых запросах. Порядок столбцов имеет значение: ключ наиболее эффективен, когда запрос фильтрует по его полезному префиксу. Столбцы с небольшой мощностью могут быть эффективными первыми элементами ключа, если по ним часто выполняется фильтрация; для рабочих нагрузок, связанных со временем, также часто полезен компонент времени. Подробные рекомендации см. в разделе Выбор первичного ключа.
В этом примере используйте (passenger_count, pickup_datetime, dropoff_datetime). passenger_count имеет мало уникальных значений и используется в фильтре по количеству пассажиров, а pickup_datetime — в агрегации по диапазону дат. Хотя pickup_datetime не является первым столбцом, ClickHouse всё равно может использовать значения из последующих столбцов ключа для исключения данных, когда по ведущему столбцу нет ограничений. Фильтрация по полезному префиксу ключа сортировки обычно обеспечивает более эффективное отсечение данных.
Примените изменение ключа сортировки
nyc_taxi.trips_small_pk, затем повторно выполните все три запроса.
Сравните результаты
Оптимизация схемы сокращает объём хранимых данных и снижает затраты на обработку выбранных значений. Ключ сортировки обеспечивает наибольшее дополнительное ускорение агрегации по диапазону дат, поскольку ClickHouse может пропускать гранулы за пределами этого диапазона. Фильтр по количеству пассажиров также считывает меньше строк, так как фильтрация выполняется по первому ключевому столбцу. Фильтр по вычисленной скорости по-прежнему считывает всю таблицу, поскольку условие фильтрации вычисляется на основе
pickup_datetime, dropoff_datetime и trip_distance, а не по полезному префиксу ключа сортировки.
Проверьте агрегацию по диапазону дат с помощью EXPLAIN indexes = 1:
В ClickHouse 25.9 и более поздних версиях эти настройки обеспечивают, что
EXPLAIN показывает используемые индексы, а также исключаемые ими части и гранулы.Примените метод к своей рабочей нагрузке
- Зафиксируйте базовые значения длительности, числа прочитанных строк и байтов, а также пикового потребления памяти.
- Проверьте, не используют ли выбранные столбцы неоправданно широкие или излишне универсальные типы.
- Внесите изменения в схему и оцените их эффект, не меняя структуру данных.
- Проверьте ключ сортировки, основанный на фильтрах, используемых в важных регулярно выполняемых запросах.
- Сравните объём выбираемых данных с помощью
EXPLAIN indexes = 1, затем повторно выполните базовые запросы в сопоставимых условиях.