Почему мои некластеризованные индексы занимают больше места при удалении строк?

22

У меня есть большая таблица с 7,5 млрд строк и 5 индексов. Когда я удаляю примерно 10 миллионов строк, я замечаю, что некластеризованные индексы увеличивают количество страниц, на которых они хранятся.

Я написал запрос, dm_db_partition_statsчтобы сообщить разницу (после - до) в страницах:

dm_db_partition_stats deltas

Индекс 1 является кластеризованным индексом, индекс 2 является первичным ключом. Другие некластеризованы и не уникальны.

Почему страницы увеличиваются в этих некластеризованных индексах?
Я ожидал, что цифры в худшем случае останутся прежними.
Я вижу, что счетчики производительности сообщают об увеличении числа страниц во время удаления.

При удалении должна ли запись-призрак перемещаться на другую страницу? Связано ли это с «уникализаторами»?

Мы находимся в процессе развертывания RCSI, но сейчас RCSI выключен.

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

Майкл Дж Сварт
источник
Просто вопрос - что произойдет при запуске REORGANIZE на одном из индексов, который вырос? Сколько страниц удалено? И если вы реорганизуетесь перед удалением, что произойдет? Я в основном думаю, что внутренним механизмам может быть проще в некоторых случаях выделить всю новую страницу и объединить, но не очищает пустые страницы. Я знаю, что REORGANIZE в конечном итоге отбрасывает значительное количество страниц, даже на относительно нефрагментированные, но большие индексы.
Смеющийся Вергилий
Хороший вопрос @LaughingVergil Когда у меня будет ответ, я вернусь сюда, чтобы сообщить об этом. (Но это может занять некоторое время).
Майкл Дж Сварт
В нашем случае это увеличение было временным явлением. При достаточном терпении очистка от призраков в конце концов выполнила свою работу, и размеры индексов уменьшились.
Майкл Дж Сварт

Ответы:

28

Один из возможных сценариев, который меня очень забавляет:

  • Строки были изначально записаны, когда в базе данных не было включено чтение зафиксированного снимка (RCSI), изоляция моментального снимка (SI) или группы доступности (AG)
  • RCSI или SI был включен, или база данных была добавлена ​​в группу доступности
  • Во время удаления в удаленные строки была добавлена ​​14-байтовая временная метка для поддержки чтения RCSI / SI / AG.

Поскольку этот сервер является основным в AG, он подвержен влиянию вторичных серверов. Информация о версии добавляется на основной - страницы данных одинаковы как на основных, так и на дополнительных. Вторичные серверы используют хранилище версий для чтения, пока строки обновляются AG, но вторичные серверы не записывают свои собственные версии метки времени на страницу. Они просто наследуют версии от работы первичного.

Чтобы продемонстрировать рост, я взял экспорт базы данных Stack Overflow (для которого не включен RCSI) и создал несколько индексов для таблицы Posts. Я проверил размеры индекса с помощью sp_BlitzIndex @Mode = 2 (скопировать / вставить в электронную таблицу и немного очистить, чтобы максимизировать плотность информации):

sp_BlitzIndex перед

Затем я удалил около половины строк:

BEGIN TRAN;
DELETE dbo.Posts WHERE Id % 2 = 0;
GO

Забавно, что в то время, как происходило удаление, файл данных увеличивался и для размещения временных меток! Отчет об использовании дисков SSMS показывает события роста - вот только верхняя часть для иллюстрации:

События роста

(Должен любить демо, где удаление приводит к росту базы данных.) Пока выполнялось удаление, я снова запустил sp_BlitzIndex. Обратите внимание, что кластеризованный индекс имеет меньше строк, но его размер уже вырос примерно на 1,5 ГБ. Некластеризованные индексы в AcceptedAnswerId значительно выросли - это индексы с небольшим значением, которое в основном равно нулю, поэтому их размеры почти удвоились!

sp_BlitzIndex во время удаления

Мне не нужно ждать окончания удаления, чтобы доказать это, поэтому я остановлю демонстрацию там. Суть в том, что: когда вы делаете большие удаления в таблице, которая была реализована до того, как были включены RCSI, SI или AG, индексы (включая кластеризованные) могут фактически расти, чтобы приспособить добавление временной метки хранилища версий.

Брент Озар
источник
3
Это объяснение. Оказывается, есть и другие обстоятельства, которые могут привести к отсутствию 14 байтов версии. В моем тестировании кажется, что перестройка индекса в автономном режиме перестроит строки без байтов версии.
Майкл Дж Сварт