user_id Int64,
attempt Int64,
duration Float64,
added_at DateTime64(3) default now64()
)
engine = MergeTree
order by (user_id, attempt)
partition by toYYYYMM(added_at);```
запросы буду делать примерно такие
```select quantile(duration) from test_duration where user_id = 10 and attempt between 0 and 50000;```
т.е. всегда буду указывать user_id и attempt. Нужно ли для более эффективного поиска указывать поле, по которому партиционирование идет, added_at?
Потестил локально
```
insert into test_duration (user_id, attempt, duration, added_at)
select toInt64(number / 10000), number % 10000, number, now64() - interval number second from numbers(1000000000);
```
и как будто никакой разницы нет с фильтром по added_at и без него - количество строк считанных с диска не меняется.
А как оно в теории работает?
так вы проверьте с фильтром added_at и без него. Это позволит не читать лишние партиции, если конечно указано поле в фильтре. А так как у вас не указано, разницы и не будет - сканирует все партиции
партиции это логическая структура и min max index внутри каждого парта... если у вас added_at в запросе в WHERE не участвует, то у вас partition pruning (отбрасывание партов из сканирование на основании значений added_at) на ранних этапах обработки запроса просто не имеет смысла ... и сканирование всегда пойдет по тем партам которые поппадают под user_id + attempt
https://youtu.be/DP7l6Swkskw?t=3777
должна быть разница и большая. У вас просто что-то с тестовыми данными, проверьте какая дата получилась в поле партиционирования
хм, до этого разницы не наблюдал, но как носом ткнули, заметил. С примером все ок. c3a2c1d2eec9 🙂 select quantile(duration) from test_duration where user_id = 10 and attempt between 0 and 5000; ┌─quantile(duration)─┐ │ 102500 │ └────────────────────┘ 1 rows in set. Elapsed: 0.032 sec. Processed 8.19 thousand rows, 196.61 KB (253.91 thousand rows/s., 6.09 MB/s.) c3a2c1d2eec9 🙂 select quantile(duration) from test_duration where user_id = 10 and attempt between 0 and 5000 and added_at between '2023-05-30 00:00:00' and '2023-05-31 00:00:00'; ┌─quantile(duration)─┐ │ 102500 │ └────────────────────┘ 1 rows in set. Elapsed: 0.005 sec. Processed 8.19 thousand rows, 262.14 KB (1.55 million rows/s., 49.52 MB/s.) на тестовом примере с added_at стабильно в 6 раз быстрее результат получаю. Т.е. лучше все же указывать поле, по которому партиционирование идет. Это ок, могу без проблем его достать. Спасибо)
пффф бред пример. Processed 8.19 thousand rows в обоих случаях у вас просто второй запрос быстрее потому что он второй и едет по кешированным данным. select count() from test_duration where added_at between '2023-05-30 00:00:00' and '2023-05-31 00:00:00'; select count() from test_duration; у вас toInt64(number / 10000) user только в одной партиции
разницу стабильно получаю, хоть в каком порядке выполнять. Точно кешируется? А как можно со сбросом кешей селект сделать? Каждый пользователь вряд ли будет дольше одного месяца жить - так и есть, он скорее всего всегда будет попадать в одну партицию, это ожидаемо.
>Каждый пользователь вряд ли будет дольше одного месяца жить - так и есть, он скорее всего всегда будет попадать в одну партицию, это ожидаемо. в общем тогда без where added_at у вас будет драка за кеш засечек. И запросы будут выполнятся по 15сек, засечки очень медленно грузятся, это трудно показать надо нагенерить много данных, чтобы размер засечек стал больше чем 5ГБ.
Обсуждают сегодня