меня есть выборка (ключ, начало периода, конец_периода) через subquery, и как натравить это на большую таблицу с фактами, чтобы выбрались нужные записи? Пока что получается только полный скан большой таблицы, т.к where работает после join
а что за запрос, почему нельзя where до join?
потому что там в where есть >= на даты, а они не умеют быть в ON
смотрите сторону engine=Join и joinGet https://clickhouse.com/docs/en/engines/table-engines/special/join#creating-a-table либо в сторону словарей SOURCE(CLICKHOUSE(query ...) LAYOUT range_hashed(...) и dictGet https://clickhouse.com/docs/en/sql-reference/dictionaries#range_hashed
может вам вместо джойна нужен range словарь? https://clickhouse.com/docs/en/sql-reference/dictionaries#range_hashed и что без join тоже фулскан по ключам сортировки? и как вообще понять проблему если запрос не показываете)
table facts (ts datetime64, key, value) primary key(ts, key) -- large table table facts_1m (ts datetime64, key, value) primary key(ts, key) -- aggregated by 1 minute. в facts_1m лежат sum(value) поминутно по ключам, например. они считаются на кроне, рандомно, на каждый ключ, версией 1 агрегации. Не вдаемся в проблемы почему так, т.к. тут я упрощаю. запрос with last_available as (select key, max(ts) maxts, max(ts)+interval 1 day maxtsneed from facts_1m group by key), -- найти последние вставленные, но не хотеть слишком много ибо ОЗУ на 1 запрос. insquery as (select toMinute(ts) tm, key, sum(value) value -- агрегация from facts f outer join last_available la on f.key=la.key -- прикрутить по ключу and f.ts>la.maxts and f.ts < la.maxtsneed group by key, tm), -- ограничить по диапазону insert into facts_1m select * from insquery -- вставить пропущенное запрос синтаксически не выдержан, но в принципе похож
первым делом я бы менял ключ сортировки в обоих таблицах на (key, ts), group by ускорится многократно а дальше уже думать над джойн
версия 1 аггрегации - был предыдущий job который запускался в произвольное время и делал агрегацию по каждому ключу от последнего раза до текущего момента. Таким образом разные ключи агрегированы последний раз в разное время. Я пишу новый job (вторая версия) и хочу одним инсертом вставить всё незааггрегированное по каждому ключу)
там так и есть в базе. Я был неточен и по памяти упрощал.
ну это хороший вариант, просто выбирать промежуток времени и вставлять всё, без проверок на каждый ключ
это да, но на текущий момент там рандомные окончания по разным ключам.
к тому же задача может появляться в подобной формулировке и в других разрезах
если ключей много и не влазят в память и нужны джойны, мы решаем разбитием на батчи например, циклом key % 10 = 0/1/2/3... в случаях когда памяти хватает но нужна скорость юзаем engine = Join ну и в свежих версиях можно попробовать поиграть с настройкой join_algorithm, иногда очень сильно ускоряет запросы
ключей мало. Проблемы с тем, что по ощущению оно не использует индекс чтобы шариться в конце таблицы фактов, а сканирует ее всю.
это не ощущение, а цифры во время select, там progress размером со всю таблицу facts
ну можно через where in попробовать отфильровать например, WHERE (key, toStartOfMinute(ts)) IN (сгенерировать поминутный range от max до max + 1 day). Будет ли разница
оно не треснет там внутри? а как генерировать range, а как их склеивать?
ну если ключей немного, то не должно треснуть для теста можно попробовать FROM facts WHERE (key, toStartOfMinute(ts)) IN (SELECT key, arrayJoin(timeSlots(max(ts), toUInt32(60 * 60 * 24), 60)) minute from facts_1m GROUP BY key)
спасибо, щас проверим
даже работает! спасибо, в этом смысле - ускорил запрос!
ради интереса, в процентах какая разница?
щас скажу.
у меня предыдущие запросы (часть селекта), генерирующие интервалы, занимают ок 20 секунд. После этого я генерирую arrayJoin, и потом прямой запрос из таблицы с фактами. Там дырка где-то 5 минут должна вернуться. Если я запрашиваю с запасом в сутки вперед и выходит большой arrayJoin, то весь запрос работает 45 секунд. Если я запрашиваю с запасом в час вперед, то работает 27 секунд. В обоих случаях возвращает около 500000 записей из таблицы (фактов) для последующей агрегации. Если старую версию брать, то уходило на десяток минут плюс по ощущениям, я ни разу не дождался, если честно. Время указано на испольнение целиком всего запроса с with...
норм) рабочая техника
теперь если бы еще оптимизировать select key, max(ts) group by key с учетом того что все индексы есть, чтобы не сканировало целиком, было бы совсем улёт 8)
так оно бы не работало так быстро, если бы индекс не юзался, покажите полный запрос и статистику по нему
Вроде уже обсуждали что order by limit по индексу пойдет. Ну или projection
да, но там ЕМНИП было для 1 ключа а тут для всех.
там была фишка с max_block_size, что полезно.
Ну можно проекцию сделать где будет max уже посчитан
я туплю, я не понимаю о чем речь.
статистику как именно смотреть?*
https://kb.altinity.com/altinity-kb-queries-and-syntax/projections-examples/
господи боже, а я не в курсе
Там внизу ссылки на видео и доки
так, добавил проекции, поиграл блоком, 9 секунд на часовой интервал, щас интервал еще сделаю динамическим... как смотреть статистику-то?
по хорошему set send_logs_level = 'trace' и дальше запрос выполнить и смотреть логи, максимально подробный вариант
вот на третьем (?) году пользования кликхаузом узнал. Это о чем говорит? Это говорит что все три года всё было и так очень отлично!
Обсуждают сегодня