Как снизить фрагментацию HEAP в SQL Server?

10

недавно я обнаружил, что одна таблица кучи имеет более 70% фрагментации. Поэтому я решил сделать

ALTER TABLE dbo.myTable REBUILD

Забавно, но потом у меня была 20% фрагментация. С тех пор на этом столе не было записи. Поэтому я решил сделать перестройку еще раз.

После 2-го раза настольная шляпа 50% фрагментации, так что даже больше! Я действительно не понимаю, как это может произойти ...

tuxmania
источник
Что вы имеете в виду, когда говорите логическая фрагментация. Это фрагментация с точки зрения использования страниц данных. Я знаю, что нет порядка, но неупорядоченные данные сами по себе не фрагментированы. Фрагментация в этом случае означает эффективное использование страниц данных.
Tuxmania
2
Я думаю, мы должны спросить, насколько большой стол? В строках и на страницах.
Коди Кониор

Ответы:

17

Что означает фрагментация в куче

Значение фрагментации в куче, которое вы получаете из столбца avg_fragmentation_in_percentпутем запроса sys.dm_db_index_physical_statsDMV, гласит, что

Логическая фрагментация для индексов или фрагментация экстентов для куч в блоке выделения IN_ROW_DATA.

Далее тот же BOL говорит, что

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

Таким образом, вы можете видеть, что это не свободное место на страницах, выделенных для Heap, а различная последовательность страниц, которая создает фрагментацию.

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

create table dbo.HeapTest
(
Id INT not NULL Default (1),
Col1   char(5000) Not null Default ('Heaps Are Cool')
)

SET NOCOUNT ON

Insert into dbo.Heaptest default values
go 50

select index_type_desc,avg_fragmentation_in_percent,fragment_count,
avg_page_space_used_in_percent,record_count
from sys.dm_db_index_physical_stats(db_id(),object_id('dbo.HeapTest','U'),0,default,'detailed')

Таким образом, таблица кучи создается с 50 записями. Ниже показано, как выглядит фрагментация после запроса DMV sys.dm_db_index_physical stats

введите описание изображения здесь

Вы можете увидеть avg_fragmentation_in_percentзначение столбца 33%. Теперь давайте посмотрим, как устроены страницы. Это можно сделать с помощью недокументированного запроса %%lockres%%. Запрос будет

SELECT  %%lockres%%, * FROM dbo.HeapTest;

И ниже, как выглядит вывод. Прикрепление только соответствующей части. Запрос выдал 50 строк, так как мы вставили 50 строк в нашу таблицу dbo.HeapTest.

введите описание изображения здесь

Он говорит, что у первой страницы есть идентификатор, 197у следующей страницы - идентификатор, у 242последующих страниц - непрерывный идентификатор, пока мы не достигнем идентификатора страницы, 264потому что после этого мы получаем идентификатор страницы 280. Таким образом, этот скачок в числах идентификаторов страниц на самом деле вызывает фрагментацию.

Теперь, чтобы не перестроить кучу и снова запустить команду, чтобы увидеть фрагментацию и порядок расположения страниц. Мы получаем фрагментацию, как

введите описание изображения здесь

Вы можете увидеть фрагментацию сейчас 14%.

Давайте посмотрим номера страниц, выделенных

введите описание изображения здесь

У нас есть только один прыжок, все страницы последовательно распределяются по идентификатору страницы. Так как только один скачок фрагментация значительно уменьшилась.

Я снова перестраиваю кучу, и теперь, когда я проверял фрагментацию, она полностью исчезла. И распределение идентификаторов страниц как

введите описание изображения здесь

Почему фрагментация увеличилась

Теперь относительно того, что могло вызвать рост фрагментации, мы можем подтвердить это тем фактом, что, когда страницы выделяются в куче, они не будут непрерывными, как вы видели выше, что вызвало увеличение значения фрагментации - это скачок идентификатора PAGE, выделенного страницам.

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

Действительно беспокоюсь о фрагментации

Если вы действительно сталкиваетесь со сценарием, в котором таблица кучи фрагментируется и замедляет запросы, лучше создать кластерный индекс для таблицы, чем перестраивать его. Причина в том, что при перестройке кучи все базовые некластеризованные индексы также перестраиваются, в результате чего процесс перестройки занимает гораздо больше времени, используя много ресурсов и раздувая журнал транзакций. В производственной системе всегда старались бы избежать этого. Павел рассказал об этом в своем разделе «Мифы о куче» .

PS: Пожалуйста, не используйте недокументированную команду в производственной системе. Это было просто для демонстрации.

Shanky
источник
Спасибо за ваш подробный анализ. Я сталкиваюсь с большими таблицами кучи, потому что некоторые энтузиасты хранилищ данных думают, что это лучше, чем использование кластерных индексов, но затем они используют множество проверочных ограничений и некластеризованных индексов в этих кучах, поэтому я не вижу преимущества кучи в этой ситуации. Однако, поскольку я всего лишь глупый разработчик, мне приходится иметь дело с этим.
Еще
Как вы запускаете select index_type_desc, avg_fragmentation_in_percent, frag_count, avg_page_space_used_in_percent, record_count из sys.dm_db_index_physical_stats (db_id (), object_id («dbo.HeapTest», только «по умолчанию», «по умолчанию», только из «U»)), возвращают из «dbo.HeapTest», «по умолчанию», 0, только «U») один стол? он возвращает для меня все индексы во всех таблицах, даже если я правильно укажу имя таблицы в 'object_id'
Микаэль
@Mickael Я использовал функцию db_id (), которая будет принимать текущую базу данных, и я специально дал имя объекта, чтобы он всегда просматривал текущую базу данных, искал Heaptestи давал результат. Я уверен, что вы могли что-то пропустить. Просто убедитесь, что уровень совместимости не равен 80, в этом случае функция db_id не работает
Shanky
@Shanky, почему бы вам не порекомендовать использовать недокументированный запрос %% lockres %% в работе? Не могли бы вы объяснить это подробно?
Ральф
@ user1624552 Просто потому, что он недокументирован, означает, что MS также не обновляет документацию по нему. Каковы его последствия, как это работает, нигде не задокументировано, поэтому об этом и спрашивают. Например, есть команда fn_dump_dblog (), которая создает скрытый планировщик, и это не хорошо. Эта команда также не поддерживается. Вы можете использовать это, но риск лежит на вас.
Шэнки