Size: a a a

ClickHouse не тормозит

2021 February 15

D

Dj in ClickHouse не тормозит
Даниил Поздеев
блин
ну когда у тебя 100 категорий, руками не прикольно писать)
^^^
источник

DK

Dmitry Kuzmin in ClickHouse не тормозит
Всем привет!
Ребят, имеется таблица вида:
CREATE TABLE events
(
   Timestamp   DateTime default now(),
   EventName   LowCardinality(String),
   UserId      UUID default generateUUIDv4(),
   /* другие колонки */
)
engine = MergeTree()
PARTITION BY (toYYYYMM(Timestamp), EventName)
ORDER BY (Timestamp, EventName)

Основная задача - считать количество уникальных UserId за диапазон времени фильтруя по EventName и при необходимости дополнительно по *другим колонкам* и выводить на график с разбивкой по часу. Например:
SELECT
   (intDiv(toUInt32(Timestamp), 3600) * 3600) * 1000 AS timestamp,
   countIf(DISTINCT UserId, EventName = 'finish') / countIf(DISTINCT UserId, EventName = 'start') AS ratio
FROM events
WHERE Timestamp > 1612781916
GROUP BY timestamp
ORDER BY timestamp

Решение в таком виде работает, но колонка UserId съедает в 10ки раз больше места, чем оставшиеся 10ки колонок.  Но подозреваю, что использование UUID для моих целей может привести к деградации производительности со временем, т.к. придется читать "жирную" колонку с диска.
Прошу накинуть:
1) Верный ли подход в целом - оптимально ли так строить запросы по подобной таблице
2) В каких кейсах используете UUID, настраиваете ли для него какое-либо сжатие не дефолтное, стоит ли ждать деградации по производительности (если забить на занимаемое место)?
источник

DC

Denny Crane [not a Y... in ClickHouse не тормозит
Dj
entering telescope :)
  with (select ['key1','key2','key3'] as arr) as all_keys
   select
       id,
       arrayElement(groupArrayInsertAt(Null, 3)(tuple(toNullable(v)), toUInt32(indexOf(all_keys, k) - 1)).1 as values, 1) as key1,
       values[2] as key2, values[3] as key3
   from
   (
   select * from (
     select arrayJoin([1,2,3]) as id, arrayJoin(['key1','key2','key3']) as k, cityHash64(id, k)%10 as v) /* random filter*/
   where v>4
   )
  group by id;
ну тут все равно перечисление полей

и есть даже такое



SELECT untuple((1, 2, 3))


┌─_ut_1─┬─_ut_2─┬─_ut_3─┐
│     1 │     2 │     3 │
└───────┴───────┴───────┘


и можно поименовать, но все равно это ничего не меняет.
источник

DC

Denny Crane [not a Y... in ClickHouse не тормозит
мне больше нравится вернуть клиенту [('a',3),('b',4)] и на клиенте разодрать
источник

D

Dj in ClickHouse не тормозит
Denny Crane [not a Yandex bot]
ну тут все равно перечисление полей

и есть даже такое



SELECT untuple((1, 2, 3))


┌─_ut_1─┬─_ut_2─┬─_ut_3─┐
│     1 │     2 │     3 │
└───────┴───────┴───────┘


и можно поименовать, но все равно это ничего не меняет.
не, мой пример именно про пивот полноценный (маппинг в колонки), у вас все таки не совсем пивот
а это можно и без перечисления:
create table default.tstpivot (id UInt32, k String, v UInt32) Engine=MergeTree order by tuple();
insert into default.tstpivot
   select * from (
     select arrayJoin([1,2,3]) as id, arrayJoin(['key1','key2','key3']) as k, cityHash64(id, k)%10 as v) /* random filter*/
   where v>4 ;
with  (select groupArrayDistinct(k) from default.tstpivot) as all_keys, -- здесь заменяем на дистинкт запрос к базе
groupArrayInsertAt(Null, 3)(tuple(toNullable(v)), toUInt32(indexOf(all_keys, k) - 1)).1 as values
   select
       id,
       values
   from default.tstpivot
group by id;
источник

DC

Denny Crane [not a Y... in ClickHouse не тормозит
Dmitry Kuzmin
Всем привет!
Ребят, имеется таблица вида:
CREATE TABLE events
(
   Timestamp   DateTime default now(),
   EventName   LowCardinality(String),
   UserId      UUID default generateUUIDv4(),
   /* другие колонки */
)
engine = MergeTree()
PARTITION BY (toYYYYMM(Timestamp), EventName)
ORDER BY (Timestamp, EventName)

Основная задача - считать количество уникальных UserId за диапазон времени фильтруя по EventName и при необходимости дополнительно по *другим колонкам* и выводить на график с разбивкой по часу. Например:
SELECT
   (intDiv(toUInt32(Timestamp), 3600) * 3600) * 1000 AS timestamp,
   countIf(DISTINCT UserId, EventName = 'finish') / countIf(DISTINCT UserId, EventName = 'start') AS ratio
FROM events
WHERE Timestamp > 1612781916
GROUP BY timestamp
ORDER BY timestamp

Решение в таком виде работает, но колонка UserId съедает в 10ки раз больше места, чем оставшиеся 10ки колонок.  Но подозреваю, что использование UUID для моих целей может привести к деградации производительности со временем, т.к. придется читать "жирную" колонку с диска.
Прошу накинуть:
1) Верный ли подход в целом - оптимально ли так строить запросы по подобной таблице
2) В каких кейсах используете UUID, настраиваете ли для него какое-либо сжатие не дефолтное, стоит ли ждать деградации по производительности (если забить на занимаемое место)?
можно хранить uniqState / uniqHLL / uniqCombi...

uniqHLL12 занимает очень мало места и очень быстро работает

https://gist.github.com/den-crane/32cac4f069f4227b35ab86553bbc649b

disk space used:
2.2M    uniqHLL12State
58M   uniqCombinedState(20)
140M    uniqState
источник

DK

Dmitry Kuzmin in ClickHouse не тормозит
Denny Crane [not a Yandex bot]
можно хранить uniqState / uniqHLL / uniqCombi...

uniqHLL12 занимает очень мало места и очень быстро работает

https://gist.github.com/den-crane/32cac4f069f4227b35ab86553bbc649b

disk space used:
2.2M    uniqHLL12State
58M   uniqCombinedState(20)
140M    uniqState
Спасибо! Поизучаю это направление
источник

D

Dj in ClickHouse не тормозит
Denny Crane [not a Yandex bot]
ну тут все равно перечисление полей

и есть даже такое



SELECT untuple((1, 2, 3))


┌─_ut_1─┬─_ut_2─┬─_ut_3─┐
│     1 │     2 │     3 │
└───────┴───────┴───────┘


и можно поименовать, но все равно это ничего не меняет.
осталось функцию unarray короче придумать :)
источник

DC

Denny Crane [not a Y... in ClickHouse не тормозит
Dj
осталось функцию unarray короче придумать :)
да можно,  но только в нее все равно до выполнения запроса придется передать кол-во колонок
источник

D

Dj in ClickHouse не тормозит
Denny Crane [not a Yandex bot]
да можно,  но только в нее все равно до выполнения запроса придется передать кол-во колонок
with () выручает.

вот только непонятно почему сюда groupArrayInsertAt(Null, 3) вместо 3 не разрешает передать скаляр из with...
источник

VB

Vladimir Bunchuk in ClickHouse не тормозит
простите за офтоп
источник

В

Владимир in ClickHouse не тормозит
Denny Crane [not a Yandex bot]
вы случайно в две реплики сразу не инсертите? что в internal_replication?
явно не указано, default = false
источник

В

Владимир in ClickHouse не тормозит
инсерчу в одну
источник

DC

Denny Crane [not a Y... in ClickHouse не тормозит
Владимир
явно не указано, default = false
ну вот все неправильно, отсюда и ошибки.

надо обязательно указать true в каждом шарде.
источник

В

Владимир in ClickHouse не тормозит
вот это поворот
источник

DC

Denny Crane [not a Y... in ClickHouse не тормозит
конечно он должен быть true при ReplicatedMergeTree иначе будут дубликаты

internal_replication=true значит что внизу Replicated и она сама internally будет делать репликацию
при internal_replication=false — репликацию делает Distributed (она пишет копию во все реплики)
источник

В

Владимир in ClickHouse не тормозит
премного, так сказать)
источник

В

Владимир in ClickHouse не тормозит
а если у меня и те и другие таблицы присутствуют?
источник

DC

Denny Crane [not a Y... in ClickHouse не тормозит
Владимир
а если у меня и те и другие таблицы присутствуют?
вы неправильно поняли что я написал. В КХ есть две репликации. Детская -- через distributed и настоящая -- через replicated. У вас сейчас обе сразу работают, детская <internal_replication>false , вам дублирует инсерты во все реплики, а потом настроящая снова дублирует, но вам везет что у вас не дублируются записи пока

короче если используете Replicated то internal_replication=true, без обсуждения.
источник

В

Владимир in ClickHouse не тормозит
да, я понял, полез фиксить )
источник