Когда таблица имеет кластеризованный индекс, индексом являются данные таблицы (в противном случае у вас есть таблица типов кучи). Перестроение кластеризованного индекса (фактически любой индекс, но пространство не будет считаться «данными» для некластеризованного индекса) приведет к объединению частично используемых страниц в более полную форму.
Когда вы вставляете данные в индекс (кластеризованный или иным образом) в конечные страницы порядка страниц, создаются по мере необходимости, и у вас всегда будет только одна частичная страница: одна в конце. Когда вы вводите данные не по порядку индексов, страницу нужно разделить, чтобы данные поместились в нужном месте: у вас получается две страницы, которые заполнены примерно наполовину, и новая строка переходит в одну из них. Со временем это может произойти много, потребляя изрядное количество дополнительного пространства, хотя в некоторой степени будущие вставки заполнят некоторые пробелы. Не листовые страницы также увидят аналогичный эффект, но реальные страницы данных имеют гораздо больший размер, чем они.
Также удаление может привести к частичным страницам. Если вы удалите все строки на странице, она будет считаться «неиспользованной», но если у нее останется одна или несколько строк данных, она все равно будет считаться используемой. Даже если на странице есть только одна строка, использующая 10 байтов, эта страница считается как 8192 байта в подсчете используемого пространства. Опять же, будущие вставки могут заполнить некоторые пробелы.
Для строк переменной длины обновления также могут иметь тот же эффект: по мере уменьшения строки она может оставлять на своей странице место, которое впоследствии будет непросто использовать повторно, а если строка на почти полной странице увеличивается в размерах, это может привести к разделению страницы. ,
SQL Server не тратит время на нормализацию данных путем изменения порядка использования страниц, пока не будет явно указано, например, порядок перестройки индекса, поскольку такие упражнения по сбору мусора могут стать кошмаром производительности.
Я подозреваю, что это то, что вы видите, хотя я бы сказал, что наличие достаточного пространства, выделенного примерно в 2,7 раза больше, чем абсолютно необходимо для данных, является особенно плохим случаем. Это может означать, что у вас есть что-то случайное в качестве одного из значимых ключей в индексе (возможно, столбец UUID), что означает, что новые строки вряд ли когда-либо будут добавлены в порядке индекса, и / или что в последнее время произошло значительное количество удалений.
Пример разделения страницы
Вставка в порядке индекса со строками фиксированной длины, четыре из которых помещаются на странице:
Start with one empty page:
[__|__|__|__]
Add the first item in index order:
[00|__|__|__]
Add the next three
[00|02|04|06]
Adding the next will result in a new page:
[00|02|04|06] [08|__|__|__]
And so on...
[00|02|04|06] [08|10|12|14] [16|18|__|__]
Теперь для добавления строк в индексном порядке (именно поэтому я использовал четные числа только выше): добавление 11
означало бы либо расширение этой второй страницы (это невозможно, поскольку они имеют фиксированный размер), перемещение всего выше 11 на одну (слишком дорого на большой индекс) или разделить страницу следующим образом:
[00|02|04|06] [08|10|11|__] [12|14|__|__] [16|18|__|__]
Отсюда добавление 13
и 17
не приведет к разделению, так как в настоящее время есть место на соответствующих страницах:
[00|02|04|06] [08|10|11|__] [12|13|14|__] [16|17|18|__]
но добавление 03 будет:
[00|02|03|__] [04|06|__|__] [08|10|11|__] [12|13|14|__] [16|17|18|__]
Как вы можете видеть, после этих операций вставки у нас в настоящее время выделено 5 страниц данных, которые могут вместить в общей сложности 20 строк, но у нас есть только 14 строк («тратя» 30% пространства).
Перестройка с параметрами по умолчанию (см. Ниже о «коэффициент заполнения») приведет к:
[00|02|03|04] [06|08|10|11] [12|13|14|16] [17|18|__|__]
сохранение одной страницы в этом простом примере. Легко увидеть, как удаление может иметь эффект, аналогичный вставкам вне индекса.
смягчение
Если вы ожидаете, что данные поступят в довольно случайном порядке по отношению к порядку индекса, вы можете использовать эту FILLFACTOR
опцию при создании или перестройке индекса, чтобы указать SQL Server искусственно оставлять пробелы для последующего заполнения - сокращая разбиения страниц в долгосрочной перспективе, но занимая больше места изначально. Конечно, неправильное использование этого значения может сделать ситуацию намного хуже, чем улучшить ситуацию, поэтому обращайтесь с ней осторожно.
Разделение страниц, особенно в кластеризованном индексе, может влиять на производительность для вставок / обновлений, поэтому FILLFACTOR
иногда настраивается по этой причине вместо проблемы использования пространства в базах данных, которые видят большую активность записи (но для большинства приложений, где чтение перевешивает записи на несколько порядков вам лучше оставить коэффициент заполнения равным 100%, за исключением особых случаев, например, когда у вас есть индексы по столбцам с фактически случайным содержимым).
Я предполагаю, что другие большие базы данных имеют аналогичную опцию, если вам нужен такой уровень контроля и в них.
Обновить
Что касается ALTER INDEX
утверждения, добавленного к вопросу после того, как я начал печатать выше: я предполагаю, что параметры такие же, как при первом построении индекса (или последнем перестроении), но если нет, то параметр сжатия может быть очень значительным, если он был добавлен, время вокруг Также в этом утверждении коэффициент заполнения установлен на 85%, а не на 100%, поэтому каждая листовая страница будет ~ 15% пустой сразу после перестроения.