Comments 5
Clickhouse way это написать код без апдейтов с учетом eventual consistency.
Получить значения с самым свежим временем воон в той колонке? Конечно. Даже без магии с массивами можно.
select
UserID,
max(ClientEventTime),
argMax(Duration, ClientEventTime) as lastDuration,
argMax(PageViews, ClientEventTime) as lastPageViews,
argMax(VisitID, ClientEventTime) as lastVisitID
from visits_v1
GROUP BY UserID
limit 100
И пусть движок ReplacingMergeTree спокойно чистит данные оставляя только самые свежие по ClientEventTime. Мы всегда вытащим только то что нужно.
Пример с данными отсюда https://play.clickhouse.com
Мутации не стоит рассматривать как усложненный аналог update. Они ни разу не транзакционные, есть риск что мерж в процессе мутации пойдёт с ошибками и тогда станет уже не весело
Чтобы это обработать, нам бы пришлось добавлять лишнюю агрегацию для каждого запроса SELECT, даже если нам не нужна информация о комментариях.
А чего не
Limit 1 By some_unique_key
Все равно ReplacingMergeTree будет быстрее чем мутация ночью.
Решение номер два. Можно же подключить внешний словарь с source, допустим, postgres и layout, например, ssd_cache. Тут конечно есть ограничение по размеру словаря, комменты или ещё какие связанные старше какого-то периода уже не отредактировать. Но опять же нам никто не мешает купить SSD дисков, 400$ за терабайт очень дёшево. Сильно дешевле чем мариновать пару сеньеров месяц на супер решение для микросервиса который будет делать селекты из кликхауса в какой-то промежуточный сторадж, программно имитировать локи для этих записей и потом делать массовую вставку записей в кликхаус обратно.
По поводу limit by. Когда экспериментировал с ReplacingMergeTree, честно говоря, limit 1 by
в голову не пришел, но все равно есть сомнения что это поможет.
При этой конструкции как я понимаю агрегация все равно выполняется, только неявно. Думаю это может значительно повлиять на производительность, но это конечно бы надо проверять.
Не уверен, что гарантируется необходимая сортировка внутри группы. Скорее всего нужно добавлять order by, чтобы мы не отсекли нужную запись.
Представим, что мы просто хотим посчитать количество сообщений. В случае с ReplacingMergeTree мы не сможем написать просто
select count(*) from message
, нам придется написать что-то типаselect count(distinct message_id) from message
, что значительно медленнее первого варианта.Этот кейс можно протестировать на https://play.clickhouse.com/ с их тестовой таблицей. Запрос
select count(*) from hits_100m_obfuscated
выполняется несколько миллисекунд.select count(distinct WatchID) from hits_100m_obfuscated
почти 10 секунд
По поводу словарей. С ними много не работал и, возможно, не до конца разобрался, но мне показалось что они не совсем подходят для нашей задачи.
смутило, что хранятся в памяти
кажется не совсем предназначены для частого обновления
усложняется логика и поддержка с добавлением отдельной бд для словаря
Возможно, в итоге этот вариант оказался бы проще и быстрее.
делать селекты из кликхауса в какой-то промежуточный сторадж, программно имитировать локи для этих записей и потом делать массовую вставку записей в кликхаус обратно
Вот это не до конца понял:)
Обновление данных в ClickHouse