в классическом понимании в кх нет?
Если так, то можно ли краткий ликбез или ссылку на то, как увеличивать перфоманс запросов, что-то я не смог ничего вменяемого найти
Если кратко, проектируете такую архитектуру таблиц, чтобы во всех запросах в секции WHERE данные сначала отсекались по ключу партицирования, а затем по убывающей по ключу сортировки
Мне кажется документация и название движка, говорит обо всём.
правильно понимаете b-tree нет вместо него есть PRIMARY KEY по которому тоже o(log n) поиск, но он по другому устроен и есть data skip indexes которые разных типов но суть в том что они помогают быстро определить что искомых данных в заданном data part нет и его сканить не надо https://clickhouse.com/docs/en/guides/improving-query-performance/skipping-indexes/ https://clickhouse.com/docs/en/guides/improving-query-performance/sparse-primary-indexes/sparse-primary-indexes-multiple/ https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree/#available-types-of-indices https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree/#functions-support почитайте попробуйте разобраться
Пытаюсь понять skip index. Есть primary key, первая колока которого дата, потом идёт id (высокая cardinality). Пытаюсь понять, как мне помочь запросам, которые пытаются быстро найти данные с WHERE id=N. Как я понимаю, мне надо skipping index чтобы найти нужный блок и гранулы в оторых все мои id сидят. Но ведь если для каждой даты будет запись для id, то этих гранул будет много, значит эффективность будет низкой? Всё равн будет всё читать чтобы из каждого id вытащить. Что не понимаю, так это какой тип индекса выбрать. Как я понял, set не подоходит? Очевидно, что id много и cardinality будет высокий в блоках. Помогите понять как тут поступить.
непонятно id у вас в PRIMARY KEY включен?
да, но он второй по порядку, после даты
при высокой кардинальности id , если он у вас еще и размазано одно значение по куче дат... скип индекс вам вообще ничего не даст, только еще больше тормозить будет и вы правильно отметили почему а при при поиске по primary key будет гранулы просканены сильно больше чем одна можно снижать index_granularity у таблицы ну там 4096, 2048, 1024 и 512 и смотреть, насколько сильно больше в памяти primary key и насколько хуже hit rate в mark cache
skip index ускоряет только тогда, когда кол-во "отброшенных по условиям skip" партов (не обязательно кол-во, затраты на проверку "в этом парте искомых значений нет" могут быть сопоставимы с чтением парта), сильно больше от кол-ва партов найденых по условиям из primary key если у вас искомые для фильтрации данные равномерно разбросаны по всем парта, скип индекс может даже еще больше тормозить
Понял. То есть корелляция с primary key важна. А в моём случае если у каждой даты есть id, то выигрыша нет никакого.
А если сделать партиции по датам?
Партиции и так по датам, но это не поможет если мы делаем запрос по одному id
Ну так а первым полем в PK сделать ID? P.S. тоже вот нет четкого понимания как работают индексы
Это можно, но как тогда быть со всеми запросами у которых date=yyymmdd? То есть все остальные запросы начнут всё сканировать.
Так по партициям читаться будет
но в таком случае все партиции будет читать всё равно при поиске по id=n? потому, что в них во всех будет ID фигурировать
Если просто по id - конечно, по индексу. Но у вас итак читается все. Но могу ошибаться. Потому что меня смущает везде фраза, что партицирование не ускоряет чтение
то есть при поиске по id он просто пойдёт в индекс, найдёт нужные гранулы (допустим их 3), в которых мой id есть и просто уж с ними будет работать. Если же по дате делаем поиск, то он отсеет все остальные парты и просто полностью просканит те, которые в моем диапазоне дат? Если так, до может и сработает.
не то чтобы все... на самом деле поскольку дата монотонно возрастает... то сначала партишен прунинг будет по дате... а потом сканирование партов опять же по дате, и поскольку дата монотонно возрастает, то может и не так уж сильно медленее будет... вы проверьте
партицирование ускоряет запросы по которым легко отбросить партиции... то есть поле и тип данных из PARTITION BY будут в запросе...
Понял, такой вариант и попробую. У нас почти все таблицы по дате партиционированы, будет интересно узнать как же для запросов по id в будущем поступать. Спасибо!
А вообще попробуйте Explain indexes=1
да, гляну, когда PK поменяю. Сейчас он сначала все парты и гранулы 2 раза читает
Если партиции созданы по типу toyyyymmdd то и в where фильтроваться тоже по этому типу нужно. Верно я понял? И вопрос а что значит буду в запросе? В блоке select?
нет, не нужно по итогу будет использоваться min/max партиции, а не выражение toYYYYMMDD то есть любое условие по дате / timestamp подойдёт
в блоке WHERE toYYYYMMDD возвращает UInt32 YYYY * 10000 + MM * 100 + DD там была какая то оптимизация. но я не помню где именно в доке это описано ли проверьте https://fiddle.clickhouse.com/b800acc5-0aff-4004-ad56-6cd2f68f61cb
как я понял если обращаться по формату создания партиции то включается оптимизатор MergeTreeWhereOptimizer и переносит фильтрацию в PREWHERE
Обсуждают сегодня