У сховищі, орієнтованому на рядки SQL, і кластерні, і некластеризовані індекси організовані як B дерева.
( Джерело зображення )
Ключова відмінність кластерних індексів від некластеризованих індексів полягає в тому, що рівень листя кластерного індексу є таблицею. Це має два наслідки.
- Рядки на кластеризованих сторінках аркуша індексу завжди містять щось для кожного (нерозріджених) стовпців таблиці (або значення, або вказівник на фактичне значення).
- Кластерний індекс - це первинна копія таблиці.
Некластеризовані індекси також можуть зробити пункт 1, використовуючи INCLUDE
пункт (Так як SQL Server 2005), щоб явно включити всі не ключові стовпці, але вони є вторинними поданнями, і завжди є ще одна копія даних навколо (сама таблиця).
CREATE TABLE T
(
A INT,
B INT,
C INT,
D INT
)
CREATE UNIQUE CLUSTERED INDEX ci ON T(A,B)
CREATE UNIQUE NONCLUSTERED INDEX nci ON T(A,B) INCLUDE (C,D)
Два вище індекси будуть майже однаковими. Що стосується індексних сторінок верхнього рівня, що містять значення для ключових стовпців A,B
та сторінок рівня аркушів, що містятьA,B,C,D
В таблиці може бути лише один кластерний індекс, оскільки самі рядки даних можуть бути відсортовані лише в одному порядку.
Вищенаведена цитата з книг SQL Server в Інтернеті викликає велику плутанину
На мою думку, це було б набагато краще сформулювати як.
На одну таблицю може бути лише один кластерний індекс, тому що рядки рівня аркуша кластеризованого індексу - це рядки таблиці.
Цитування книг в Інтернеті невірно, але вам повинно бути зрозуміло, що "сортування" як некластеризованих, так і кластерних індексів є логічним не фізичним. Якщо ви читаєте сторінки на рівні аркушів, дотримуючись зв'язаного списку та читаючи рядки на сторінці в порядку масиву слотів, тоді ви будете читати індексні рядки в упорядкованому порядку, але фізично сторінки можуть бути не сортовані. Поширена думка, що з кластерним індексом рядки завжди фізично зберігаються на диску в тому ж порядку, що і індексний ключ , помилково.
Це було б абсурдною реалізацією. Наприклад, якщо рядок вставлено в середину таблиці 4 Гб, SQL Server не повинен копіювати 2 ГБ даних у файл, щоб звільнити місце для щойно вставленої рядки.
Натомість відбувається розкол сторінки. Кожна сторінка на рівні аркушів як кластерних, так і некластеризованих індексів має адресу ( File:Page
) наступної та попередньої сторінки в порядку логічного ключа. Ці сторінки не повинні бути ні суміжними, ні ключовими.
наприклад, ланцюжок пов’язаних сторінок може бути 1:2000 <-> 1:157 <-> 1:7053
Коли трапляється розділення сторінки, нова сторінка виділяється з будь-якої точки файлової групи (зі змішаної міри, для невеликих таблиць, або з порожнього рівномірного обсягу, що належить цьому об'єкту, або новопризначеного рівномірного обсягу). Це може бути навіть у одному файлі, якщо група файлів містить більше одного.
Ступінь, в якій логічний порядок і суміжність відрізняється від ідеалізованої фізичної версії, - це ступінь логічної фрагментації.
У новоствореній базі даних з одним файлом я запустив наступне.
CREATE TABLE T
(
X TINYINT NOT NULL,
Y CHAR(3000) NULL
);
CREATE CLUSTERED INDEX ix
ON T(X);
GO
--Insert 100 rows with values 1 - 100 in random order
DECLARE @C1 AS CURSOR,
@X AS INT
SET @C1 = CURSOR FAST_FORWARD
FOR SELECT number
FROM master..spt_values
WHERE type = 'P'
AND number BETWEEN 1 AND 100
ORDER BY CRYPT_GEN_RANDOM(4)
OPEN @C1;
FETCH NEXT FROM @C1 INTO @X;
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO T (X)
VALUES (@X);
FETCH NEXT FROM @C1 INTO @X;
END
Потім перевірте макет сторінки
SELECT page_id,
X,
geometry::Point(page_id, X, 0).STBuffer(1)
FROM T
CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% )
ORDER BY page_id
Результати були всюди. Перший рядок у ключовому порядку (значення 1 - підкреслено стрілкою внизу) знаходився майже на останній фізичній сторінці.
Фрагментація може бути зменшена або усунена шляхом перебудови або реорганізації індексу для збільшення кореляції між логічним порядком і фізичним порядком.
Після бігу
ALTER INDEX ix ON T REBUILD;
Я отримав таке
Якщо в таблиці немає кластерного індексу, вона називається купою.
Некластеризовані індекси можуть бути побудовані або на купі, або на кластерному індексі. Вони завжди містять локатор рядків назад до базової таблиці. У разі купи це фізичний ідентифікатор рядків (позбавлений) і складається з трьох компонентів (Файл: Сторінка: Слот). У випадку кластерного індексу локатор рядків є логічним (кластерний індексний ключ).
В останньому випадку, якщо некластеризований індекс вже природно включає стовпці ключів CI або як стовпці ключів NCI або INCLUDE
стовпці -d, тоді нічого не додається. В іншому випадку відсутній стовпець ключів CI мовчки додається до NCI.
SQL Server завжди забезпечує, щоб ключові стовпці були унікальними для обох типів індексу. Механізм, за яким це застосовується для індексів, які не оголошені унікальними, відрізняється, проте, між двома типами індексів.
Кластеризовані індекси uniquifier
додаються для будь-яких рядків з ключовими значеннями, що дублюють існуючий рядок. Це просто висхідне ціле число.
Для некластеризованих індексів, не оголошених унікальним SQL Server, мовчки додає локатор рядків у некластеризований індексний ключ. Це стосується всіх рядків, а не лише тих, які насправді є дублікатами.
Кластеризована порівняно з некластеризованою номенклатурою також використовується для індексів магазину стовпців. У статті Удосконалення стовпців Stores SQL Server станів
Хоча дані зберігання стовпців насправді не «кластеризовані» на жодному ключі, ми вирішили зберегти традиційну конвенцію SQL Server щодо посилання на первинний індекс як кластерний індекс.