Якщо у таблиці є кластерний індекс, індекс - це дані таблиці (інакше у вас є таблиця типу купи). Перебудова кластерного індексу (фактично будь-який індекс, але простір не вважатиметься "даними" для некластеризованого індексу) призведе до об'єднання частково використаних сторінок у більш повну форму.
Коли ви вставляєте дані в індекс (кластеризований чи іншим способом) у порядку порядку, індекс сторінки створюються за потребою, і ви завжди матимете лише одну часткову сторінку: ту, що знаходиться в кінці. Коли ви вводите дані з порядку індексу, сторінку потрібно розділити, щоб дані вмістилися в потрібному місці: ви отримуєте дві сторінки, які приблизно наполовину заповнені, і новий рядок переходить в одну з них. З часом це може трапитися багато, затрачаючи неабияку кількість додаткового простору, хоча певною мірою майбутні вставки заповнять частину прогалин. Подібний ефект також побачить нелистові сторінки, але фактичні сторінки даних значно більші за розміром, ніж вони.
Також видалення може призвести до часткових сторінок. Якщо ви видалите всі рядки на сторінці, вона вважається "невикористаною", але якщо в ній залишився один чи більше рядків даних, вони все ще вважаються як використовувані. Навіть якщо на сторінці є лише один рядок, що використовує 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% одразу після відновлення.