SQL Server значительно замедлил удаление по индексам - PullRequest
5 голосов
/ 15 января 2010

Я запускаю архивный скрипт, который удаляет строки из большой (~ 50 м записи БД) на основе даты их ввода. Поле даты является кластеризованным индексом в таблице и, следовательно, к чему я применяю свое условное утверждение.

Я выполняю это удаление в цикле while, пробуя от 1000 до 100 000 записей в пакете. Независимо от размера партии, это удивительно медленно; что-то вроде 10 000 записей, удаляемых за минуту. Глядя на план выполнения, много времени уходит на «удаление индекса». В таблице около 15 полей, и примерно у 10 из них есть какой-то индекс. Есть ли способ обойти эту проблему? Я даже не уверен, почему каждый раз удаление индекса занимает так много времени, может кто-нибудь пролить свет на то, что здесь происходит? Это образец моего плана выполнения:

альтернативный текст http://img94.imageshack.us/img94/1006/indexdelete.png

(последовательность указывает на команду удаления)

Эта база данных активна и часто вставляется, поэтому я не решаюсь использовать метод копирования и усечения для обрезки размера. Есть ли другие варианты, которые я здесь упускаю?

Ответы [ 5 ]

6 голосов
/ 15 января 2010

Удаление 10 тыс. Записей из кластеризованного индекса + 5 некластеризованных записей не должно занимать 1 минуту. Похоже, у вас действительно очень медленный подсистема ввода-вывода. Какие значения для:

  • Avg. Дисковая сек / запись
  • Avg. Диск с / Чтение
  • Avg. Длина очереди записи на диск
  • Avg. Длина очереди чтения с диска

На каждом диске, участвующем в операции (включая журналы!). Если вы поместили индексы в отдельные файловые группы и разместили каждую файловую группу для своего собственного LUN или собственного диска, то вы можете определить, какие индексы являются более проблематичными. Кроме того, сбрасывание журнала может быть серьезным узким местом. SQL Server здесь не имеет большого контроля, все в ваших руках, как ускорить процесс. это время не тратится на циклы ЦП, тратится на ожидание завершения ввода-вывода, и вам нужна подсистема ввода-вывода, откалиброванная для требуемой нагрузки.

Чтобы уменьшить нагрузку ввода-вывода, вам нужно сделать индексы более узкими. Прежде всего, убедитесь, что кластеризованный индекс является самым узким из возможных. Затем убедитесь, что некластеризованные индексы не содержат неиспользуемые большие столбцы (я видел это ...). Основное преимущество можно получить, включив сжатие страниц . И, наконец, проверьте статистику использования индекса в sys.dm_db_index_usage_stats и посмотрите, подходит ли какой-либо индекс для топора.

Если вы не можете значительно уменьшить нагрузку ввода-вывода, попробуйте разделить ее. Добавьте файловые группы в базу данных, переместите большие индексы в отдельные файловые группы, поместите файловые группы в отдельные пути ввода-вывода (отдельные шпиндели).

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

3 голосов
/ 15 января 2010

Предположим, что для каждой записи в таблице имеется 5 индексных записей.

Теперь каждое удаление - это, по сути, 5 операций.

Добавьте к этому, у вас есть кластерный индекс. Заметьте, что время удаления кластерного индекса огромно? (В 10 раз) длиннее других индексов? Это потому, что ваши данные реорганизуются с каждой удаленной записью.

Я бы предложил сбросить хотя бы этот индекс, выполнить массовое удаление, а не повторно Индексные операции по удалению и вставке по своей природе являются дорогостоящими. Одна перестройка, скорее всего, будет намного быстрее.

2 голосов
/ 15 января 2010

Второе предложение, которое @NickLarsen высказал в комментарии. Узнайте, есть ли у вас неиспользуемые индексы и отбросьте их. Это может снизить накладные расходы на удаление индекса, что может быть достаточным улучшением, чтобы сделать операцию более своевременной.

Еще одна более радикальная стратегия - удалить все индексов, выполнить удаление, а затем быстро воссоздать индексы для теперь меньшего набора данных. Это не обязательно прерывает обслуживание, но, вероятно, может сделать запросы намного медленнее. Хотя я не являюсь экспертом по Microsoft SQL Server, поэтому вы должны принять мой совет по этой стратегии с небольшим количеством соли.

1 голос
/ 15 января 2010

Для его реализации потребовалась бы некоторая работа, учитывая, что это в работе, но если вы работаете на SQL Server 2005/2008, вам нужно исследовать и преобразовать таблицу в разделенную, тогда удаление старых данных может быть достигнуто очень быстро.Он разработан для эффекта типа «скользящего окна» и предотвращает крупномасштабные удаления, связывающие таблицу / процесс.

К сожалению, с производственной таблицей, переход на эту технику потребует некоторого кодирования T-SQL,знания и выходные, чтобы обновить / перенести его.После того, как все существующие операции выбора и вставки будут работать без проблем, обслуживание и добавление / удаление разделов - вот где вам нужен t-sql для управления процессом.

1 голос
/ 15 января 2010

Больше обходного пути, но вы можете добавить флаг IsDeleted в таблицу и обновить его до 1 вместо удаления строк? Вам нужно изменить свои SELECTs и UPDATEs, чтобы использовать этот флаг.

Затем вы можете запланировать удаление или архивирование этих записей в нерабочее время.

...