Улучшить производительность удаления sql и уменьшить размер файла журнала и tempDB?

У меня огромная база данных, она ежедневно обрабатывает почтовый трафик. В системе необходимо удалять старые письма каждый день:

Delete from EmailList(nolock) 
WHERE EmailId IN ( 
    SELECT EmailId 
    FROM Emails 
    WHERE EmailDate < DATEADD([days], -60, GETDATE())
)

Это работает, но проблема в том, что это занимает много времени и файл журнала становится очень большим из-за этого. Размер файла журнала увеличивается более чем на 100 ГБ каждый день.

Я думаю, что мы можем изменить это на

Delete from EmailList(nolock) 
WHERE EXISTS ( 
    SELECT EmailId 
    FROM Emails 
    WHERE (Emails.EmailId = EmailList.EmailId) AND 
        (EmailDate < DATEADD([days], -60, GETDATE()))
)

Но кроме этого, есть ли что-то, что мы можем сделать, чтобы улучшить производительность. больше всего уменьшить размер файла журнала?

  • EmailId проиндексирован.

3 ответа

Я видел

GetDate()-60

синтаксис стиля выполняет НАМНОГО лучше, чем

DATEADD([days], -60, GETDATE()))

особенно если в столбце даты есть индекс. Несколько коллег-администраторов и я потратили немало времени, пытаясь понять, ПОЧЕМУ он будет работать лучше, но результат был в пудинге.

Еще одна вещь, которую вы, возможно, захотите рассмотреть, учитывая объем записей, которые, я полагаю, вам нужно удалить, - это разбиение удалений на группы, скажем, 1000 или 10000 записей. Это, вероятно, ускорит процесс удаления.

[РЕДАКТИРОВАТЬ]:

относительно комментария @TomTom: если у вас есть доступная редакция SQL Server Enterprise, вам следует использовать разбиение таблиц.

Если это не так, мой оригинальный пост может быть полезным:


[ОРИГИНАЛЬНАЯ ПОЧТА]

Удаление большого количества данных всегда сложно. Я столкнулся с той же проблемой, и я выбрал следующее решение:

В зависимости от ваших требований это не сработает, но, возможно, вы сможете извлечь из этого некоторые идеи.

Вместо использования 1 таблицы используйте 2 таблицы с одинаковой схемой. Создайте синоним (я предполагаю, что вы используете сервер MS SQL), который указывает на "активную таблицу из 2 таблиц (означает, что это активная таблица, в которую вы сейчас записываете). Используйте этот синоним для вставок в приложении или вместо использования синонима приложение может просто изменять таблицу каждые x дней, в которые оно пишет.

Каждые x дней вы можете обрезать старую / неактивную таблицу, а затем воссоздать синоним, чтобы указать на усеченную таблицу (если вы используете решение synonnym), так что вы эффективно разделяете данные за раз.

Вы должны синхронизировать переключатель активной таблицы. Я полностью автоматизировал это, используя общую блокировку приложения для приложения и эксклюзивную блокировку приложения при изменении синонима (== блокировка пишущего приложения во время процесса переключения).

Если изменение кода вашего приложения не является вариантом, рассмотрите возможность использования того же принципа, но вместо записи в синоним, с которым вы могли бы создать представление вместо триггеров (операция вставки вставила бы в "активный" раздел). Код триггера должен был бы syhcnronize, используя что-то вроде Applock, как упомянуто выше (так что запись во время работы процесса переключения).

Мое решение немного сложнее, поэтому в настоящее время я не могу опубликовать здесь код, но он работает без проблем для приложений с высокой нагрузкой, и процесс swithcingt/cleanup полностью автоматизирован.

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

Другие вопросы по тегам