Я управляю приложением, которое имеет очень большой (почти 1 ТБ данных с более чем 500 миллионами строк в одной таблице) серверной части базы данных Oracle. База данных на самом деле ничего не делает (ни SProcs, ни триггеры, ни что-либо еще), это просто хранилище данных.
Каждый месяц мы обязаны удалять записи из двух основных таблиц. Критерии очистки различаются и представляют собой комбинацию возраста строки и пары полей состояния. Обычно мы чистим от 10 до 50 миллионов строк в месяц (добавляем около 3-5 миллионов строк в неделю за счет импорта).
В настоящее время мы должны сделать это в пакетах по 50000 строк (т.е. удалить 50000, comit, удалить 50000, зафиксировать, повторить). Попытка удалить весь пакет за один раз приводит к тому, что база данных перестает отвечать на запросы примерно на час (в зависимости от количества строк). Такое удаление строк в пакетах очень сложно для системы, и мы обычно должны делать это «как позволяет время» в течение недели; постоянное выполнение сценария может привести к снижению производительности, что неприемлемо для пользователя.
Я считаю, что этот вид пакетного удаления также снижает производительность индекса и оказывает другие воздействия, которые в конечном итоге приводят к снижению производительности базы данных. В одной таблице 34 индекса, и размер данных индекса фактически больше, чем сами данные.
Вот сценарий, который один из наших ИТ-специалистов использует для этой очистки:
BEGIN
LOOP
delete FROM tbl_raw
where dist_event_date < to_date('[date]','mm/dd/yyyy') and rownum < 50000;
exit when SQL%rowcount < 49999;
commit;
END LOOP;
commit;
END;
Эта база данных должна быть на 99.99999%, и у нас есть только 2-дневный интервал обслуживания один раз в год.
Я ищу лучший способ удаления этих записей, но я еще не нашел ни одного. Какие-либо предложения?
источник
Ответы:
Логика с «A» и «B» может быть «скрыта» за виртуальным столбцом, в котором вы можете выполнить разбиение:
источник
Классическим решением этого является разделение ваших таблиц, например, по месяцам или по неделям. Если вы не сталкивались с ними раньше, секционированная таблица похожа на несколько идентично структурированных таблиц с неявным
UNION
выбором при выборе, и Oracle автоматически сохранит строку в соответствующем разделе при ее вставке на основе критериев разделения. Вы упоминаете индексы - ну, у каждого раздела тоже есть свои разделенные индексы. В Oracle очень дешевая операция по удалению раздела (это аналогTRUNCATE
с точки зрения нагрузки, потому что это то, что вы действительно делаете - усечение или удаление одной из этих невидимых вложенных таблиц). Это будет значительный объем обработки для разделения «по факту», но нет смысла плакать над пролитым молоком - преимущества такого перевешивания перевешивают затраты. Каждый месяц вы делите верхний раздел, чтобы создать новый раздел для данных следующего месяца (вы можете легко автоматизировать это с помощьюDBMS_JOB
).А с разделами вы также можете использовать параллельный запрос и исключение разделов , что должно сделать ваших пользователей очень счастливыми ...
источник
A
то», еслиDateA
он старше 3 лет, он очищается. Если статусB
иDateB
старше 10 лет, он очищается. Если мое понимание разбиения верно, то разбиение не будет полезным в такой ситуации (по крайней мере, в отношении очистки).Один аспект, который следует учитывать, - это то, сколько производительности удаления зависит от индексов, а сколько - от необработанной таблицы. Каждая запись, удаленная из таблицы, требует одинакового удаления строки из каждого индекса btree. Если у вас есть более 30 индексов btree, я подозреваю, что большую часть времени вы тратите на обслуживание индексов.
Это влияет на полезность разбиения. Скажем, у вас есть индекс на имя. Стандартный индекс Btree, все в одном сегменте, возможно, должен сделать четыре перехода, чтобы добраться от корневого блока к листовому блоку, и пятое чтение, чтобы получить строку. Если этот индекс разделен на 50 сегментов и у вас нет ключа разделения в качестве части запроса, то каждый из этих 50 сегментов необходимо будет проверить. Каждый сегмент будет меньше, поэтому вам, возможно, придется сделать только 2 прыжка, но вы все равно можете сделать 100 операций чтения, а не предыдущие 5.
Если они являются растровыми индексами, уравнения разные. Вы, вероятно, не используете индексы для идентификации отдельных строк, а скорее их наборы. Таким образом, вместо запроса с использованием 5 операций ввода-вывода для возврата одной записи, он использовал 10 000 операций ввода-вывода. Таким образом, дополнительные издержки в дополнительных разделах для индекса не будут иметь значения.
источник
удаление 50 миллионов записей в месяц партиями по 50000 - это всего 1000 итераций. если вы делаете 1 удаление каждые 30 минут, это должно соответствовать вашим требованиям. запланированное задание для запуска отправленного вами запроса, но удаляющего цикл, чтобы он выполнялся только один раз, не должно вызывать заметного переоценки среди пользователей. Мы производим примерно столько же записей на нашем заводе, который работает в режиме 24/7 и отвечает нашим потребностям. На самом деле мы распространяем чуть более 10 000 записей каждые 10 минут, что выполняется за 1 или 2 секунды на наших серверах Oracle unix.
источник
Если на диске недостаточно места, вы можете создать «рабочую» копию таблицы, скажем
my_table_new
, с помощью CTAS («Создать таблицу как выбор») с критериями, при которых записи будут отбрасываться. Вы можете выполнить оператор create параллельно и с подсказкой добавления, чтобы сделать это быстро, а затем построить все свои индексы. Затем, как только он закончил (и протестировал), переименуйте существующую таблицу вmy_table_old
и переименуйте «рабочую» таблицу вmy_table
. После того, как вам будет удобно все,drop my_table_old purge
чтобы избавиться от старого стола. Если есть множество ограничений внешнего ключа, взгляните наdbms_redefinition
пакет PL / SQL . Он будет клонировать ваши индексы, ограничения и т. Д. При использовании соответствующих опций. Это краткое изложение предложения Тома Кайта из AskTomизвестность. После первого запуска вы можете автоматизировать все, и создание таблицы должно выполняться намного быстрее, и это может быть сделано при работающей системе, а время простоя приложения будет ограничено менее чем минутой до переименования таблиц. Использование CTAS будет намного быстрее, чем удаление нескольких пакетов. Этот подход может быть особенно полезен, если у вас нет лицензии на разделение.Пример CTAS с сохранением строк с данными за последние 365 дней и
flag_inactive = 'N'
:источник
при удалении раздела вы оставляете глобальные индексы непригодными для использования, которые нужно перестраивать, перестройка глобальных индексов будет большой проблемой, так как если вы сделаете это онлайн, это будет довольно медленным, в противном случае вам понадобится простои. в любом случае, не может соответствовать требованию.
«Обычно мы чистим от 10 до 50 миллионов строк в месяц»
Я бы порекомендовал использовать пакетное удаление PL / SQL, несколько часов, я думаю.
источник