(примерная)
CREATE TABLE test1 (
id UInt16,
tp UInt16,
ag UInt16,
date DateTime
) ENGINE = MergeTree()
PARTITION BY toStartOfInterval(date, INTERVAL 4 HOUR)
ORDER BY (id, tp, ag);
При вставке хочу агрегировать с нее данные в view1, чтобы оставлять только уникальные строки по секции ORDER BY,
также хочу иметь возможность дропнуть данные с MV, по партиции. Таблица на миллионы записей, FINAL для Replace не до конца убирает дубликаты.
Идеи, которые пришли в голову
-- v1
CREATE MATERIALIZED VIEW t1_agg ENGINE = AggregatingMergeTree()
PARTITION BY toStartOfInterval(result_date_utc, INTERVAL 4 HOUR)
ORDER BY (id, tp, ag) POPULATE
AS SELECT
id, tp, ag,
result_date_utc
FROM T1
GROUP BY id, tp, ag, toStartOfInterval(result_date_utc, INTERVAL 4 HOUR) as result_date_utc;
-- v2
CREATE MATERIALIZED VIEW t1_agg_max ENGINE = AggregatingMergeTree()
PARTITION BY toStartOfInterval(result_date_utc, INTERVAL 4 HOUR)
ORDER BY (id, tp, ag) POPULATE
AS SELECT
id, tp, ag,
max(result_date_utc) as result_date_utc
FROM T1
GROUP BY id, tp, ag;
-- v3
CREATE MATERIALIZED VIEW t1_agg_max_state ENGINE = AggregatingMergeTree()
ORDER BY (id, tp, ag) POPULATE
AS SELECT
id, tp, ag,
maxState(result_date_utc) as result_date_utc
FROM T1
GROUP BY id, tp, ag;
Из-за особенностей вставки данных ощутимой разницы между v1 и v2 не будет.
Возможно небольшое изменение процесса, тогда v2 будет лучше в агрегации, но менее точен при дропе партиций (из-за мах берем самую большую дату, которая может оказаться через несколько партиций от минимальной)
Можно ли как-то в v3 запихнуть state еще в PARTION? Пока идея только при селекте добавить where на поле. и хранить все что есть
если коротко, то никак. Окончательная дедубликация всегда в финальном запросе. Будет это какой-нибудь group by или final - зависит от конкретных данных и их потоков. Идея сделать дедубликацию в MV - порочна изначально, т.к. MV работает с блоками поступающих данных, а не со всей таблицей.
а делать дедупликацию на основе Replacing MV тоже не правильно? может есть какие-то особенности вызовы FINAL к DISTRIBUTED? Это запрос с FINAL, но данные все равно дублируются
да, final with ReplacingMV with Distributed - это проблема. Distributed соберет вместе результаты нескольких FINAL, но дубликаты между шардами удалять не будет. Поэтому ваш путь - argMax/group by.
а в чем преимущество argMax? я вообще сделал через DISCTINCT, работает быстрее GROUP BY 2-3 с, против 7-8
argMax - это один из механизмов дедубликации. Не всегда просто посчитать uniq по данным, среди которых есть дубликаты. Особенно если требуется полная точность (uniqExact). Разговор изначально был про distributed конфигурацию и дубликатами рассыпанными по разным шардам. Простой distinct тут не особо поможет, если нужна полная точность. Но лучше закатать губу и считать какой-нибудь uniqHLL12 - он ещё быстрее, но не гарантирует полной точности.
Почему DISCTINCT не может? Если выполню его на distributed SELECT DISTINCT s_id, o_id, a_id, codes FROM data_mv_Replacing FINAL;
почитайте изначальный вопрос (не мой). У человека этот final обрабатывался на шардах, а после сборки вместе получалось больше чем нужно, потому как final дубликаты между шардами не поборет.
Это был мой вопрос ) FINAL чистит дубликаты на шардах (их 2), DISCTINCT в данных, что пришли с шадрдов, грубо говоря Или это не совсем так работает? Мне нужно совсем без дубликатов
если ключ шардирования сделан так что дубликаты получаются (и разрешаются) внутри шардов, то проблемы нет. Если вы считаете distinct по единственному id в order by (где происходит дедубликация) - проблем нет. Но в других случаях есть риск получить неточность - значения из "лишних" строк, которые были на разных шардах и не смогли дедублицироваться попадут в хеш-таблицу дистинкта.
я бы ещё внимательно прочитал https://clickhouse.com/docs/en/operations/settings/settings/#optimize-distributed-group-by-sharding-key и попробовал применить.
Обсуждают сегодня