Почему моя база данных все еще фрагментирована после того, как я перестроил и переиндексировал все?

41

У меня есть база данных, которую я пытался дефрагментировать все таблицы одновременно с помощью этого T-SQL:

SELECT 
        'ALTER INDEX all ON ' + name + ' REORGANIZE;' + CHAR(10) +
        'ALTER INDEX all ON ' + name + ' REBUILD;'
    FROM sys.tables

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

Я запустил это, чтобы определить, что у меня все еще есть фрагментация:

SELECT * FROM 
sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL) 
WHERE avg_fragmentation_in_percent > 0

И я получил:

database_id object_id   index_id    partition_number    index_type_desc alloc_unit_type_desc    index_depth index_level avg_fragmentation_in_percent    fragment_count  avg_fragment_size_in_pages  page_count  avg_page_space_used_in_percent  record_count    ghost_record_count  version_ghost_record_count  min_record_size_in_bytes    max_record_size_in_bytes    avg_record_size_in_bytes    forwarded_record_count  compressed_page_count
85  171147655   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   36.3636363636364    5   2.2 11  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  421576540   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   75  7   1.14285714285714    8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  965578478   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   14.7058823529412    6   5.66666666666667    34  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1061578820  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   40  4   1.25    5   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1109578991  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   30.7692307692308    5   2.6 13  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1205579333  2   1   NONCLUSTERED INDEX  IN_ROW_DATA 2   0   50  5   1.6 8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1493580359  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   50  6   1.66666666666667    10  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL

Я знаю, что мне не хватает чего-то очень простого, но я не знаю что.

Джастин Даринг
источник
Какие ошибки вы получили? И есть ли причина, по которой вы это реорганизуете и перестраиваете то же самое?
Шон Мелтон
Шон, я прошу прощения за то, что пропустил одно слово. Я не получил ни одного ошибок. Что касается того, почему я выполнил обе команды, я сделал это после того, как попробовал каждую команду в отдельности. Я обновил свои вопросы.
Джастин Даринг

Ответы:

38

Столы крошечные. Количество страниц в ваших таблицах:

11, 8, 6, 5, 13, 8, 10

Они занимают 480 КБ в общей сложности. Там буквально нечего дефрагментировать.

Изменить: это требует немного больше объяснений.

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

Более широко используемые сценарии дефрагментации (пара примеров, приведенных ниже) имеют тенденцию исключать небольшие таблицы из-за этого. IIRC, <500 страниц в одной или обеих. При таких размерах выгода от дефрагментации очень мала, а показатели фрагментации потенциально искажены распределением экстентов со смешанными размерами.

Марк Стори-Смит
источник
Хорошо, это удовлетворительно, если только у кого-то нет лучшего ответа, я отмечу ваш как правильный.
Джастин Даринг
3
+1 Договорились с Марком. Беспокойство по поводу фрагментации, когда у вас есть некоторые данные. :-)
Аарон Бертран
Я полностью понимаю, что вы говорите. Но это просто из любопытства, потому что движок БД просто не может дефрагментировать такие несколько страниц? Я имею в виду, должна быть причина для этого.
Томас Стрингер
3
Дело не в том, что это не может, но зачем это беспокоить? Это практически не повлияет на ввод-вывод - тем более что таблицы такого размера почти гарантированно останутся в памяти.
Аарон Бертран
1
Только что. Кажется странным, вот и все. Скажем, я пишу приложение для проверки и составления отчета о фрагментации индекса, мне нужно добавить дополнительную логику не только для проверки процента фрагмента, но и для количества страниц, чтобы не было ложных тревог.
Томас Стрингер
19

Цитата из « Рекомендации по дефрагментации индекса Microsoft SQL Server 2000 »:

«Фрагментация влияет на дисковый ввод-вывод. Поэтому сосредоточьтесь на больших индексах, поскольку их страницы с меньшей вероятностью будут кэшироваться SQL Server. Используйте количество страниц, сообщаемое DBCC SHOWCONTIG, чтобы получить представление о размере индексов (каждая страница 8 КБ.) Как правило, вас не должны беспокоить уровни фрагментации индексов с менее чем 1000 страниц. В тестах индексы, содержащие более 10 000 страниц, показали повышение производительности, при этом наибольший прирост по индексам - при значительно большем количестве страниц (больше чем 50000 страниц) . "

Так что этот вид отвечает на ваш вопрос и поддерживает ответы Марка и Аарона.

Вы можете найти хорошую информацию о фрагментации индекса в следующих статьях от Brent Ozar:

Кроме того, множество полезной информации об индексах в целом (а также о проблемах фрагментации) можно найти в блоге Кимберли Триппа .

Мэриан
источник
12

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

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'ALTER INDEX all ON ' + name + ' REBUILD;
    ' FROM sys.tables;

PRINT @sql; -- to see the first 8,000 characters and make sure it checks out
-- EXEC sp_executesql @sql;
Аарон Бертран
источник
Аарон, спасибо за указание на динамический sql, я хорошо знаю динамический sql, я не собирался автоматизировать решение, пока оно не заработало. Тем не менее, другие читающие это должны знать.
Джастин Даринг