184 похожих чатов

Добрый день, здравствуйте! Можете, пожалуйста помочь. Таблица работает на движке ReplacingMergeTree,

логика такая: у нас есть компонент в системе, который выполняет какую-то работу, попутно сохраняя "снимки" данных в процессе. Условно, начал работу — сделал снимок, произошло какое-то событие в системе — сделал снимок и так далее. Идея ясна. Все они имеют почти идентичные значение полей (например, отличается last_event_time).

У клиента есть желание видеть самые актуальные значения в реальном времени. В базе у нас содержатся "дубликаты", из которых нужно выбрать один самый актуальный. При каждом запросе чистить дубликаты (а Clickhouse это позволяет) слишком дорого. Для меня решением стал запрос:

SELECT
argMax(hex(id), last_event_time)
argMax(field_1, last_event_time),
argMax(field_2, last_event_time),
FROM (
SELECT id, field_1, field_2, field_3, last_event_time -- ...
FROM table_1
WHERE (service_timestamp > toDateTime64('1694165200', 6, 'UTC') AND service_timestamp < toDateTime64('1696957199', 6, 'UTC'))
UNION ALL
SELECT id, field_1, field_2, field_3, last_event_time -- ...
FROM table_2
WHERE (service_timestamp > toDateTime64('1694165200', 6, 'UTC') AND service_timestamp < toDateTime64('1696957199', 6, 'UTC'))
)
GROUP BY (id)
ORDER BY (service_timestamp) ASC
LIMIT 0, 100;

argMax() вернет строку m с максимальным значением n.

m | n
1 | 2
1 | 3
2 | 4
4 | 4

SELECT argMax(m, n) .. GROUP BY (m)
===============================
1 | 3
2 | 4
4 | 4

Однако при большом наборе полей памяти используется невероятно много. Вопрос: как обычно решается такая проблема? Именно Best Practice.

Я не администратор, опыта работы с базами данных у меня мало. Буду признателен за помощь!

10 ответов

10 просмотров

argMax вполне good practice. Еще вариант, выбрать максимальное значение timestamp и сджойнить с основной таблицей SELECT * FROM (SELECT * FROM table) as full RIGHT SEMI JOIN (SELECT max(service_timestamp) as service_timestamp, id ) as maxTime USING service_timestamp, id

Алексей Осипов
Не тяжеловатый джойн будет ?

С ограничениями по Where нормально. В чистом виде конечно не пойдет

из БД в ПЗУ такое грести накладно.. Проще на коленке написать отдельную приложуху на любом ЯП или использовать Redis и постоянно обновлять по ключу данные.. Тоже пример "на котиках", но логику вы поймёте: есть N светофоров - id 1, 2, 3,... и в каждый момент времени у вас поступает связка: (id, сигнал(зел/жел/кр), timestamp) -> в редиску перезаписывать для каждого id: 1, кр, 1696912696 3, зел, 1696912697 ... Если у вас ваши поля НЕ огромные, вы там не храните видео и прочее и оборудования - не миллиарды миллиардов, тогда вы в каждый момент времени имеете САМЫЕ просто актуальные данные и достаточно получить их из редиски той же по ключу - это считанные миллисекунды, даже учитывая, если у вас редиска будет далеко.. А как вам советуют с джойнами и прочим - это накладно ОЧЕНЬ - "из пушки по воробьям". Посмотрите в сторону in-memory хранения последнего стейта, чтоб не выгребать.. БД всё же нужна для ретроспективы у вас, а не для последнего стейта..

Владислав-Белоусов Автор вопроса
DaiTenshi
из БД в ПЗУ такое грести накладно.. Проще на колен...

Приложение, которое генерирует снимки данных, как раз работает с Redis. И занимается планированием — там он к месту. А Clickhouse работает в качестве исторической справки. Тут он используется по назначению: клиенты могут захотеть выгрузить и посмотреть на историю за прошлую неделю, месяц или даже год. Тут Redis не поможет, к сожалению)

Владислав Белоусов
Приложение, которое генерирует снимки данных, как ...

Для ретро - запрос в клик, последнее в редиске в качестве хранилища ключ-значение. Видимо, там редиска используется как мессадж бас. А раз редиска уже есть, почему бы не выделить там ещë kvp хранилище? Я не говорил, что вам не нужна ретроспектива, но для последних значений лучшей практикой будет подрубить in-memory kvp хранилище.

Владислав-Белоусов Автор вопроса
DaiTenshi
Для ретро - запрос в клик, последнее в редиске в к...

Слишком большой объём данных. У нас огромный трафик, и Clickhouse себя зарекомендовал великолепно) С этим помощь не нужна, спасибо). Мне нужна только помощь с оптимизацией запроса)

Сделать mv с AggregatingMT движком и argMaxState не вариант? У нас похожий кейс, нужно выдавать статусы на максимальную дату, по сути текущие статусы. Уникальных записей под полмиллиона, размер - единицы гигабайт за год на диске всего

Владислав-Белоусов Автор вопроса
Ivan Torgashov
Сделать mv с AggregatingMT движком и argMaxState н...

Я в эту сторону не смотрел, спасибо, обязательно посмотрю. Тут как раз выше кидали статью с MV. А насколько ощутима разница между "оптимизированным запросом" и MV было в вашем случае, если не секрет? Я вот добился неплохой производительности просто добавив LIMIT внутрь подзапроса: SELECT argMax(hex(id), last_event_time) argMax(field_1, last_event_time), argMax(field_2, last_event_time), FROM ( SELECT id, field_1, field_2, field_3, last_event_time -- ... FROM table_1 WHERE (service_timestamp > toDateTime64('1694165200', 6, 'UTC') AND service_timestamp < toDateTime64('1696957199', 6, 'UTC')) LIMIT 0, 100; -- добавил тут UNION ALL SELECT id, field_1, field_2, field_3, last_event_time -- ... FROM table_2 WHERE (service_timestamp > toDateTime64('1694165200', 6, 'UTC') AND service_timestamp < toDateTime64('1696957199', 6, 'UTC')) LIMIT 0, 100; -- добавил тут ) GROUP BY (id, ...) ORDER BY (...) ASC LIMIT 0, 100;

Владислав Белоусов
Я в эту сторону не смотрел, спасибо, обязательно п...

в исходной таблице несколько миллиардов записей, допустим для миллиона уникальных клиентов. При аггрегации все это схлапывается до миллиона получается, по ним и идёт поиск по дата+стейт, либо просто стейт (в нашем случае с датой), даже за год всего 365млн строк, боюсь даже посчитать сколько в сырой будет за это время (храним макс. несколько месяцев оригинал). Так вот по MV поиск по конретному клиенту менее одной секунды, по сырью ддо нескольких минут, в зависимости от нагрузки

Похожие вопросы

Обсуждают сегодня

Типа вызывать GetParent и проверять на соответствие GetModuleHandle?
The Bird of Hermes
67
Всем привет! Кто нибудь парсил в ручную JSON без библиотек и фреймворков? Есть может ссылки на оптимальный алгоритмы работы с текстом и примеры таких парсеров?
Lem
27
Do any of you guys have interesting projects one could join? I'm a Middle Full-Stack developer (JS/TS, React & Node)
Lev Shapiro
40
Есть сайт. Там была древняя версия эво. Стоял плагин, который каждый коммент в Jot делал отдельной страницей. После обновления все слетело, теперь старница открывается отдельн...
Artem
1
$res = json_decode($наша строка из респонса); $res1 = array_map(fn($o) => $o->name, $res->breadcrumbs[0]->entities); Как такое будет на Хаскеле?.. В начале весь джейсон, в ко...
Хаскель Моисеевич Гопник
27
Добрый день. А shovel'ы можно как-то сконфигурировать в definitions.json? Пробовал что-то вроде: { "users": [ { "name": "agent", "password_hash": "RBCbTzQd...
Aleksey
1
Вопрос по диагностике ошибок (я знаю в чем, в данном конкретном примере, я знаю, как исправить, пример модельный, понятно, что в реальности бывает намного запутаннее). module...
ⰄⰎⰋⰐⰐⰑⰛⰤⰧⰧⰩⰄ ⰊⰑⰁⰓⰡⰛⰦⰕⰫ
11
В чем сила брат, в NASM или FASM?
Isaac Kleiner
18
А чем вам питонисты не угодили?😂
.
79
Есть какой-нибудь для Delphi/FPC T*Compression(Decompression)Stream на базе LZ4/Zstd/любой другой быстрый(и хорошо сжимающий) алгоритм А ещё лучше в pure pascal А ещё лучше од...
notme
52
Карта сайта