сделать: есть относительно небольшая таблица 100+ млн строк, 30-40 столбцов. В ней нужно удалять раз в сутки старые записи, ttl не подходит поскольку то что нужно удалить - вычисляемое множество. Иногда выдаёт memory limit error - видно в логах мутаций. Что можно сделать, мб уменьшить кол-во обработчиков фоновых процессов?
Если вычисляемое множество, то и выборка мутации подозреваю тоже по нему работает рассчитывая на лету. Соответственно по памяти падает потому что запрос слишком сложный/долгий. И ответ из этого, материализуейте вычисляемое множество в реальную колонку, и удаляйте по ней хоть в ttl
По ttl всё равно не получится. Может я не точно выразился, попробую перефразировать: из таблицы выбираются те id, что уже неактуальны и это не критерий времени, далее удаляются всё эти id. Запрос там достаточно простой, без джойнов. Потому могу предположить что просто выборка не влезает в память, хм, может выборку тупо лимитом ограничить
покажите запрос. сколько мутаций одновременно запускается?
Alter table... Delete where id in (select id from... Where...) ; Падало на 1 мутации с количеством parts_to_do 300+
Я бы на дверь показал, а когда пришел разбираться тот, кто на работу взял, СБ вызвал.
Первое, что приходит в голову, это делать delete in partition - находишь партиции, которые будут изменены, и по ним по отдельности делаешь удаление Ещё можешь найти партиции, которые будешь менять, создать временную таблицу (полноценную копию оригинала), через insert вставить в неё строки из изменяемых партиций с фильтром и потом через replace partition вставить в оригинальную таблицу
Можно попробовать, спасибо
раз в день удалять надо именно через мутации (желательно IN PARTITION но автоматический прунинг тоже есть давно уже). мутации по памяти вообще не должны падать. у вас какие-то сложные условия в where?
мутации могут падать, если их не через словарь делают а через сложный запрос
В условии отобрать все id которых нет в словаре, словарь содержит актуальные записи. Словарь 30+ млн строк и 2 столбца. В памяти занимает 4 Гб.
ну, поэтому и спросил про "что там в WHERE" коллега удаляет, не обновляет... но мало ли что там в WHERE
WHERE dictHas() ?
Вообще, это не самое правильное использование кликхауса, удаление данных мутациями, это последнее что надо делать. Это не MySQL, и для ваших данных возможно правильнее использовать его, а для аналитики уже переливать из MySQL в кликхаус (есть даже движок подходящий) Прочитайте про разницу между OLAP и OLTP. С таким подходом и количеством обрабатываемых партиций, проблема будет расти как снежный ком с ростом количества данных. У вас после удаления данных все эти партиции должны будут перестроиться и смержиться под новые индексы, и так каждый раз, пока вы не столкнетесь с тем что будет недостаточно и места для выполнения операции. Я бы пересмотрел архитектуру и способ хранения данных. Или как другую костыльную альтернативу использовал VersionedCollapsingMergeTree или ReplacingMergeTree для "обнуления" нужных вам строк, а не удаления
если дело не в том, что критически нужно высвобождать место, а просто "отключать" ненужные id, для меня выглядит логичнее сделать это через колонку is_active или is_deleted (на ваш вкус) и поверх таблицы просто прикрутить вью, которая по этой колонке фильтрует. потом на старых cold партициях где-нибудь в 3 утра запускать физическое удаление таких строк.
Не логичней, ведь тогда придётся делать апдейт этой колонки, когда id станет неактуальным - что тоже будет тяжело для КХ.
бесспорно, но вроде как апдейты по логике должны быть гораздо легче "физически" для системы, чем удаления
Where dictGet(dictionary, dict. Attribute, table.Key) = table. Attribute что-то вроде латерального запроса к справочнику в памяти
как минимум если колонок в таблице больше, чем одна)
Почему? И там и там насколько я понял читая статью на Хабре происходит клонирование куска, вычищение лишнего из куска или обновление в нём данных и потом замена новым куском - старого?
так как система колоночная, то (как я понимаю), чтобы сделать апдейт нужно обработать один "файл-колонку", а для удаления — столько же, сколько столбцов в таблице
у вас перебор, так нельзя вы удаляете по двум полям? если так делайте словарь с композитным ключем на два поля...
Почему нельзя? Работает же, и причём быстро достаточно...
хотя да, так тоже будет быстро... но память есть не должен совсем. может память кто-то другой съедает? у вас словарь не автообновляемый?
Вы либо обновляете минимальный файл с uint8 изменяя 0 или 1. Либо удаляет и пересобираете парт в партиции по всем столбцам, вроде вывод очевиден
Авто обновляемый, может кто то другой - этот вариант я тоже прорабатываю
Всем спасибо за помощь в вопросе, в итоге переспал) с вашими идеями ночь и придумал свой вариант. - удаляю материализованный столбец если он есть is_actual - 9 секунд. (alter table ... drop column if exists) - Создаю материализованный столбец в основной таблице is_actual в котором из словаря сразу рассчитываю его актуальность. 1-3 секунды (alter table ... add column if not exists ...) - далее делаю alter table ... delete where is_actual = 0 and date_modify < today() — чтобы не зацепить те данные что в процессе укладки (допущение, но не планируется запускать такую чистку сразу в начале дня, часа в 3 ночи - там уже все будет уложено точно. date_modify - дата вставки строки в таблицу - дефолт на стороне КХ) - жду 15-30 секунд - мутация успешно завершена. - профит.
Обсуждают сегодня