
fikfok
10.08.2018
12:54:08

Slach
10.08.2018
13:25:35

Kirill
10.08.2018
13:31:40


fikfok
10.08.2018
13:39:13
Как выглядит запрос на создание въюхи, какие запросы делаете и что ожидаете увидеть?
Создание:
CREATE MATERIALIZED VIEW td_stats.mvw_td_stats_site_zone_position_all_resp_by_15minute
ENGINE = AggregatingMergeTree(created_date, (created_date, position_id), 8192) POPULATE
as
select
created_date,
toStartOfFifteenMinutes(created) as created_15minute,
site_id,
zone_id,
position_id,
countState() as total,
uniqState(user_id) as unique
from td_stats.td_stats
group by created_date, toStartOfFifteenMinutes(created), site_id, zone_id, position_id
Запрос к матвью (время работы ~450 мс):
select
created_15minute as date,
toInt32(countMerge(total)) as total,
toInt32(uniqMerge(unique)) as unique
from td_stats.mvw_td_stats_site_zone_position_all_resp_by_15minute
where position_id = 6103
group by created_15minute
order by created_15minute
Запрос к таблице с детальными данными (время работы ~170 мс !!!):
select
toStartOfFifteenMinutes(created) as date,
toInt32(count()) as total,
toInt32(uniq(user_id)) as unique
from td_stats.td_stats
where position_id = 6103
group by toStartOfFifteenMinutes(created)
order by toStartOfFifteenMinutes(created)

Google


Kirill
10.08.2018
13:47:48
Создание:
CREATE MATERIALIZED VIEW td_stats.mvw_td_stats_site_zone_position_all_resp_by_15minute
ENGINE = AggregatingMergeTree(created_date, (created_date, position_id), 8192) POPULATE
as
select
created_date,
toStartOfFifteenMinutes(created) as created_15minute,
site_id,
zone_id,
position_id,
countState() as total,
uniqState(user_id) as unique
from td_stats.td_stats
group by created_date, toStartOfFifteenMinutes(created), site_id, zone_id, position_id
Запрос к матвью (время работы ~450 мс):
select
created_15minute as date,
toInt32(countMerge(total)) as total,
toInt32(uniqMerge(unique)) as unique
from td_stats.mvw_td_stats_site_zone_position_all_resp_by_15minute
where position_id = 6103
group by created_15minute
order by created_15minute
Запрос к таблице с детальными данными (время работы ~170 мс !!!):
select
toStartOfFifteenMinutes(created) as date,
toInt32(count()) as total,
toInt32(uniq(user_id)) as unique
from td_stats.td_stats
where position_id = 6103
group by toStartOfFifteenMinutes(created)
order by toStartOfFifteenMinutes(created)
1) Для данного набора колонок у вас достаточно странный ПК
2) Если версия КХ >= 18.1.0, то смысла использовать AggregatingMergeTree нет, берите Summing и храните стейты только для того что нужно, например тотал легко считается без хранения состояния.


fikfok
10.08.2018
13:56:38
Что ещё не понятно так это общие количества строк - они разные:
select count() from
(
select
toStartOfFifteenMinutes(created) as date,
toInt32(count()) as total,
toInt32(uniq(user_id)) as unique
from td_stats.td_stats
where
position_id = 6103
group by toStartOfFifteenMinutes(created)
order by toStartOfFifteenMinutes(created)
)
select count() from
(
select
created_15minute as date,
toInt32(countMerge(total)) as total,
toInt32(uniqMerge(unique)) as unique
from td_stats.mvw_td_stats_site_zone_position_all_resp_by_15minute
where
position_id = 6103
group by created_15minute
order by created_15minute
)
Первый возвращает 1374, второй - 127.


Denis
10.08.2018
14:33:41
toInt32(uniq(user_id)) as unique -- это нельзя посчитать в MV.
u +u+u
1+1+1 = 3, а должно быть 1

fikfok
10.08.2018
14:42:11

Denis
10.08.2018
14:43:00
ясно, я не заметил.
но тогда как уже правильно заметили в order by нужен created_15minute
чтобы для каждого значения created_15minute хранились стейты

fikfok
10.08.2018
14:55:25

Denis
10.08.2018
14:57:43
блин, в моей голове новый синтаксис partition by order by, я про ключ схлапывания AggregatingMergeTree, который PK aka sortkey
AggregatingMergeTree(created_date, (created_date, position_id, created_15minute)

fikfok
10.08.2018
14:59:38
> > AggregatingMergeTree(created_date, (created_date, position_id, created_15minute)
Надо будет попробовать. Спасибо за совет!

Denis
10.08.2018
15:03:08
ну и если вы пишете
group by created_date, toStartOfFifteenMinutes(created), site_id, zone_id, position_id
то логично все тоже самое перечислить и в PK
тогда агрегаты будут хранится для всех комбинаций значений
created_date, toStartOfFifteenMinutes(created), site_id, zone_id, position_id

fikfok
10.08.2018
15:07:14
ну и если вы пишете
group by created_date, toStartOfFifteenMinutes(created), site_id, zone_id, position_id
то логично все тоже самое перечислить и в PK
Да, матвью с таким определением AggregatingMergeTree(created_date, (created_date, created_15minute, position_id), 8192) POPULATE возвращает такое же количество записей как и запрос к таблице с детальными данными. Хоть с этим разобрался.
Но время выполнения почему-то больше у матвью. У матвью около 800 мс, у запроса к таблице с детальными данными около 170 мс.

Google

Denis
10.08.2018
15:10:00
скорее всего uniqMerge работает медленно.
сколько строк во вью и сколько в таблице? optimize final ?
быстро будет потом, когда не нужно будет ходить в таблицу и считать count поднимая данные за месяц, можно будет сходить во вью и посчитать сумму, взяв готовые каунты для всех 15 мин. интервалов, т.е. когда во вью будет млн строк, а в таблице миллиард.
а хотя с другой стороны, может и не будет быстрее, надо же все равно домерживать, т.е. во вью будет
u,u1,u2,u4
u,u1,u2,u3
u11,u111

fikfok
10.08.2018
15:21:36
Запустил
optimize table td_stats.TMP_mvw_td_stats_site_zone_position_all_resp_by_15minute final
Теперь запрос к матвью отрабатывает за около 1.6 с. Время увеличилось вдвое.
Что я делаю не так?


Denis
10.08.2018
15:36:46
не знаю, вот мой тест 0.009 MV vs 0.148 Table
drop table z; drop table mvz;
create table z(d Date, u String) Engine=MergeTree partition by tuple() order by tuple();
CREATE MATERIALIZED VIEW mvz ENGINE = AggregatingMergeTree(d, (d), 8192) as select d, uniqState(u) as us from z group by d
insert into z select today(), concat('usr',toString(rand()%664579)) from numbers(10000000);
insert into z select today()-1, concat('usr',toString(rand()%664579)) from numbers(10000000);
select (uniqMerge(us)) as unique from mvz group by d order by d;
┌─unique─┐
│ 662715 │
│ 662715 │
└────────┘
2 rows in set. Elapsed: 0.009 sec.
select (uniq(u)) as unique from z group by d order by d;
┌─unique─┐
│ 662715 │
│ 662715 │
└────────┘
2 rows in set. Elapsed: 0.148 sec. Processed 20.00 million rows, 396.65 MB (135.45 million rows/s., 2.69 GB/s.)
правда у меня строки схлапываются и во вью совсем мало строк (CH 18.6.0)
ну и если строк много и все запросы типа where position_id = 6103, я бы position_id поставил первым в PK чтобы спускаться сразу к нему


fikfok
10.08.2018
15:49:36
матвью пересоздал с прежним ключём. Время запроса по конкретному position_id прежнее - около 700-800 мс. Пересоздал матвью с ключом, в котором position_id поставил на первое место. Время выполнения запроса по position_id стало лучше - около 350 мс. Но всё равно, на таблице с детальными данными запрос отрабатывает быстрее - 170 мс.
матвью пересоздал с прежним ключём. Время запроса по конкретному position_id прежнее - около 700-800 мс. Пересоздал матвью с ключом, в котором position_id поставил на первое место. Время выполнения запроса по position_id стало лучше - около 350 мс. Но всё равно, на таблице с детальными данными запрос отрабатывает быстрее - 170 мс.
Точнее так. Новое матвью создал совсеми ключами, какие перечислены в селекте, но position_id поставил на первое место:
AggregatingMergeTree(created_date, (position_id, created_date, created_15minute, site_id, zone_id), 8192) POPULATE


Denis
10.08.2018
15:55:33
ОК. А сколько строк и какое время
select count()
from td_stats.mvw_td_stats_site_zone_position_all_resp_by_15minute
where position_id = 6103

fikfok
10.08.2018
15:58:39
select count() from td_stats.TMP_mvw_td_stats_site_zone_position_all_resp_by_15minute where position_id = 6103
1 374 стр. За 12 мс.
select count() from td_stats.td_stats where position_id = 6103
1 862 345 стр. За 22 мс.

Denis
10.08.2018
16:02:24
тогда сделайте еще одно вью без site_id, zone_id
иначе неравноценное сравнение

fikfok
10.08.2018
16:07:21
тогда сделайте еще одно вью без site_id, zone_id
иначе неравноценное сравнение
Матвью с только position_id:
CREATE MATERIALIZED VIEW td_stats.TMP_mvw_td_stats_only_position_all_resp_by_15minute
ENGINE = AggregatingMergeTree(created_date, (position_id, created_date, created_15minute), 8192) POPULATE
as
select
created_date,
toStartOfFifteenMinutes(created) as created_15minute,
position_id,
countState() as total,
uniqState(user_id) as unique
from td_stats.td_stats
group by created_date, toStartOfFifteenMinutes(created), position_id
Запрос с выбором конкретного position_id:
select
created_15minute as date,
toInt32(countMerge(total)) as total,
toInt32(uniqMerge(unique)) as unique
from td_stats.TMP_mvw_td_stats_only_position_all_resp_by_15minute
where
position_id = 6103
group by created_15minute
order by created_15minute
Время выполнения около 500 мс. Стало хуже.


Denis
10.08.2018
16:32:49
ну не знаю, возможно у вас такие хитрые юзеры, может из-за времени,
у меня MV делает таблицу, и если много уникальных пользователей и если мало
https://gist.github.com/den-crane/a72614fbe6d23eb9c2f1bce40c66893f

fikfok
10.08.2018
16:46:42

Denis
10.08.2018
19:00:45

Necromant
10.08.2018
19:04:12

Denis
10.08.2018
19:09:49
300 T или 300 Г ? От запросов зависит и их количества, посчитать тяжело, просто 16 сильно мало, особенно если запросы будут перетряхивать 300Г а потом агрегировать в памяти например 10, наверняка у вас под кеш линукса осталось 4.

Necromant
10.08.2018
19:10:39
300Gb, опечатался

Google

Necromant
10.08.2018
19:11:49
тоесть я правильно понимаю, что больше важна тут ОЗУ, чем само дисковое хранилище?

Wolf
11.08.2018
00:36:05

Alexey
11.08.2018
01:34:13
Доброе утро, правильно я понимаю, что после INSERT батча в MergeTree движках новые данные для SELECT будут доступны сразу после завершения INSERT. Но если я хочу использовать специфику типа Summing/Collapsing/Replacing то мне нужно чтоб случился merge либо ипользовать FINAL ?

Kirill
11.08.2018
04:19:16

Aleksandr
11.08.2018
05:46:17
Привет. Подскажите пожалуйста, использую движок ReplacingMergeTree делаю count получаю 1.7млн записей делаю count с final получаю 580к записей, делаю optimize table но записи все равно не чистятся и результаты получаю такие же самые, в чем может быть причина? Ключ версии выбрал поле типа DateTime

Tima
11.08.2018
06:13:42

Aleksandr
11.08.2018
06:23:19
Спасибо, попробую


Alexey
11.08.2018
06:59:42
Подскажите, какой Engine использовать для следующего кейса: постоянно создаются и меняются новые объекты (до 100 000 в сек) для разных пользователей, объект может быть в 3 состояниях - Started -> InProgress -> Completed (иногда Started->Completed), нужно считать количество объектов в каждом состоянии по каждому пользователю и выдавать их список за какой-то диапазон времени. Изменение состояния большинства объектов происходит в течние минуты. Финальное состояние хотелось бы видеть сразу в SELECT, а не после непредсказуемого merge. Первое, что приходит в голову, - вставлять запись о каждом состоянии в MergeTree (но непонятно, как выбирать только последний стейт каждого объекта) или ReplacingMT и делать SELECT FINAL (но, по тому, что я читал, скорость выборки падает в разы), а так же делать AggregatedMT MV для каждого состояния, чтоб считать объекты в каждом состоянии.
Есть какие-то best practice для подобной задачи в КХ?


Aleksandr
11.08.2018
07:01:07
MergeTree
Например так:
2 поля start / complete
0 / 0 - start
1 / 0 - in progress
1 / 1 - complete
Всегда можно узнать состояние

Slach
11.08.2018
07:02:17

Aleksandr
11.08.2018
07:02:31
Ну или просто progress поле с 3 состояниями
И типом UInt8
Update на сколько я знаю только начинают вводить в кодовую базу

Slach
11.08.2018
07:03:22
Как из него последнее состояние выбрать?

Aleksandr
11.08.2018
07:04:09
Where progress=3 если 1 поле
И
Where start =1 and complete =1

Slach
11.08.2018
07:04:25
Last_value partition by насколько я знаю нет
Это не последнее состояние

Aleksandr
11.08.2018
07:04:54
Последнее состояние чего?

Google

Slach
11.08.2018
07:05:08
Объекта
Финальное состояние человек хочет в select

Aleksandr
11.08.2018
07:05:33
Update это по сути
select with change 1 field
На данный момент
Ну
select count(*) from table where start =1 and complete=1

Саша
11.08.2018
07:06:15
argMax не подходит ?

Aleksandr
11.08.2018
07:06:29
Если делать с 1 поле то подходит
Если ввести поле progress с 3 состояниями

Slach
11.08.2018
07:07:09
Ок :) все теперь и я знаю про argmax

Aleksandr
11.08.2018
07:07:20
0 - start
1 - in progress
2 - complete
В любой момент времени можно узнать когда и сколько и каких было состояний

Alexey
11.08.2018
07:08:42
спасибо, а как выбрать список объектов с последними состоянями до того как мердж не прошел?

Aleksandr
11.08.2018
07:09:38
А он и не пройдет
При MergeTree у вас остаются все 3 записи
Это более надёжно для вашей задачи

Alexey
11.08.2018
07:10:13
то есть делать клиентскую обработку?

Aleksandr
11.08.2018
07:10:42
Да
Тогда вы не потеряете свои данные
А старые всегда можно сделать detach

Google

Aleksandr
11.08.2018
07:11:13
И куда то сложить

Alexey
11.08.2018
07:11:14
фактически на 100 записей мне приедет 300 состояний, я перед дальнейшей обработкой откидываю 200?

Billiardball
11.08.2018
07:13:47
MergeTree
objectKey | state | userId | date
select count(), state, userId from table where date between .... and ... group by state, userId order by date desc limit 1 by objectKey, state, userId

Alexey
11.08.2018
07:22:41
а state надо в PK включать? или достаточно user-id?

Billiardball
11.08.2018
07:24:34
Как хотите) Я бы objectKey и userId ток в пк добавил)

Alexey
11.08.2018
07:25:25
спасибо, буду пробовать на реальных данных

Dmitry
11.08.2018
07:25:28


Denis
11.08.2018
11:10:17
Подскажите, какой Engine использовать для следующего кейса: постоянно создаются и меняются новые объекты (до 100 000 в сек) для разных пользователей, объект может быть в 3 состояниях - Started -> InProgress -> Completed (иногда Started->Completed), нужно считать количество объектов в каждом состоянии по каждому пользователю и выдавать их список за какой-то диапазон времени. Изменение состояния большинства объектов происходит в течние минуты. Финальное состояние хотелось бы видеть сразу в SELECT, а не после непредсказуемого merge. Первое, что приходит в голову, - вставлять запись о каждом состоянии в MergeTree (но непонятно, как выбирать только последний стейт каждого объекта) или ReplacingMT и делать SELECT FINAL (но, по тому, что я читал, скорость выборки падает в разы), а так же делать AggregatedMT MV для каждого состояния, чтоб считать объекты в каждом состоянии.
Есть какие-то best practice для подобной задачи в КХ?
Если это игра и результаты запроса нужны не для анализа постфактум, а для хода игры, то не полетит, кх eventual consistent и время выполнения запросов непредсказуемо и слишком медленно для маленьких выборок.


Alexey
11.08.2018
15:06:22
И доп фильтры по завершенным/незавершенным
Большого кол-ва SELECT быть не должно
@den_crane правильно я понимаю, если у меня несколько реплик данных и SELECT будут приходить на разные машины, то это повысит SELECT request rate?
@count0ru я нашел случайно на гитхабе твою репу с КХ под кубер, хотел поинтересоваться, взлетело?

Denis
11.08.2018
16:38:56
Ну да, можно больше запросов делать. И можно тяжёлые запросы выполнять сразу двумя репликами, но это не всегда помогает и ускоряет не кратно числу реплик.

Alexey
11.08.2018
16:43:44