помогает просто unix timestamp вместо time юзать, даже минус не нужен 0.2 сек vs 11 сек CREATE TABLE logs_time_dt ( `time` DateTime64(9), `project` LowCardinality(String) CODEC(ZSTD(7)), `service` LowCardinality(String) CODEC(ZSTD(7)), `message` String CODEC(ZSTD(7)), `tags_hash` Array(UInt64) ) ENGINE = MergeTree PARTITION BY toDate(time) ORDER BY (project, service, toUnixTimestamp64Nano(time))
ORDER BY project DESC, service DESC, time DESC
а эта штука тут не работает? Support optimize_read_in_order if prefix of sorting key is already sorted. E.g. if we have sorting key ORDER BY (a, b) in table and query with WHERE a = const ORDER BY b clauses, now it will be applied reading in order of sorting key instead of full sort. #32748 (Anton Popov).
похоже там все еще хуже чем кажется
При таком explain plan actions=1 … меняется с ReadType: InReverseOrder на ReadType: Default
жесть, что происходит вообще
как и в случае с советом вот этим где предлагается поменять ключ сортировки
это из-за LowCardinality, т.е. by design, слона я не заметил
Можешь пояснить?)
Слишком много мелких чтений генерирует, даже если взять начальную схему и сделать селект с optimize_read_in_order = 0 всё драматически меняется) Было Merge sorted 20001 blocks, 20000 rows in 15.54792904 sec. Стало с SETTINGS optimize_read_in_order = 0 Merge sorted 13 blocks, 20000 rows in 0.203999065 sec
у меня примерно те же результаты если в project и service убрать LowCardinality. В твоём примере с гитхаба в запросе стоит limit
ага, но казалось бы оптимизатору лучше знать? Я разверну немного контекст, видимо это тоже нужно, это не единственный запрос который гоняется к таблице, поэтому workaround в стиле “а вот здесь оно сломается, поэтому делаем по-другому” делать сложно на более стандартном для логов кейсе вида: where message like ‘%foo%’ order by time desc limit 10000 запросы работают как надо, а если сортировку поменять или убрать optimize_read_in_order, то не как надо Не хочется здесь выбирать среди двух стульев
я всегда думал что оптимизатора(CBO) нет в КХ, он просто по колонкам из запроса пытается понять можно ли применить оптимизацию или нет, но статистики нет. И это не всегда работает) Возможно разработчики вам что-то смогут подсказать К таблице у меня только вопрос зачем granularity 1024? вам часто нужны выборки по 1 строке? Не замедляют ли запросы skipping index с granularity 1 + маленький granularity у таблицы.
его и нет, ты прав
сделал песочницу со всеми видами запросов. SET optimize_read_in_order = 0; https://fiddle.clickhouse.com/ba6e3a90-c41c-4680-ab77-06614f49cd6b SET optimize_read_in_order = 1; https://fiddle.clickhouse.com/dc407df3-099e-4515-beb5-832f619c75e7
https://fiddle.clickhouse.com/7e2923e4-905e-489d-81fc-9bae576f1b80
https://fiddle.clickhouse.com/2be9767a-40ea-40ee-b85a-6288b2a24669 сделал гранулярность 3 - еще хуже
Гранулярность для таблицы скорее из идеи что “меньше данных читать за точечными запросами наверное лучше”. Какого-то исследования перфоманса на продакшен-данных не проводили, так что тут не скажу. Замерить при каких значениях будет лучше или хуже кажется непросто Про гранулярность data skipping index - он в количестве гранул измеряется, а не в количестве строчек. У нас результат запроса это обычно сотни или тысячи строчек. Хотя в каких-то случаях с точечным поиском чего-то очень конкретного могут быть и меньше. Про замеры опять же тут только смотрели какие-то выборочные запросы, что да, по логам оно какие-то гранулы очень неплохо скипает для определённых запросов.
это норма для кластерного индекса, ниче не поделать, сортируйте по полям по которым фильтр есть всегда и с низким selectivity
у нас скорее кейс “хотим фильтровать по всему подряд”. Где-то как раз data skipping indexes с этим помогают
да, но тогда я б все равно сортировал по полю с максимальной кардинальностью сначала... порядок очень сильно влияет
ну и в запросах надо PREWHERE делать
Так там 3 поля, сортировка по time, остальные 2 константные, а в PREWHERE нужные поля вроде как сами попадают неплохо
тут главное понимать распределение данных, у вас синтетический пример в котором tags_hash это просто по порядку идут значения от 0 до 3000, и получается с гранулярностью 1024 вы довольно просто можете отфильтровать гранулу, если сделать в инсерте [ number % 8196 ] всё ещё быстрее станет. Вы уверены что у вас в реальности в проде такие упорядоченные данные?) Самое главное в skipping индексах изучить распределение по гранулам)
да, грубо говоря у нас льются мегабайты логов в секунду. отсортированные по timestamp и в аттрибутах есть айди операции, операций параллельных - тысячи, если не больше
зачем вам константные поля в индексе? встроенный prewhere optimization - плох на любом запросе сложнее чем 2+2
они в запросе константные, префикс ключа всегда там присутствует. Если речь о том чтобы поменять ordering key таблицы, я не уверен что так станет лучше про prewhere хочется примеры, на примере выше оно не особо на что-то влияет, с такими случаями не сталкивался, так что тут ничего внятного сказать не смогу
ну тоесть в tags_hash уникальных значений единицы и они редко повторяются?
сложность в том, что это логи сервисов. сегодня одно может быть, завтра другое)
я понимаю, я к тому что синтетический тест не показатель, вот вам супер быстрый запрос, потому что значения реже повторяются и большие гранулы. Прикиньте хотябы минимально распределение чтобы подобрать оптимально и не замедлить https://fiddle.clickhouse.com/21bfe473-2b4a-419c-8c83-caf7e05ce046
нужно что бы два запроса работали приемлимо. один "простой" с лимитом и фильтром по мессадж и сложный с хешом
Обсуждают сегодня