Похоже, что кластерный ключ добавляется (ко всем) промежуточным узлам неуникального некластеризованного индекса.И по той же логике RID добавляются к промежуточным узлам в случае некластеризованной таблицы (?)
Да, это правда.
Это сделано для улучшения удобства обслуживанияиндекс.
Скажем, у вас есть дополнительный (некластеризованный) индекс для column
, 1,000,000
записей с column = 1
и вы хотите удалить одну из этих записей.
запись также должна быть удалена из индекса.
Чтобы найти удаляемую запись, необходимо выполнить поиск B-Tree
по индексу.Но если узлы ветвления не сохраняли значение указателя строки (будь то кластеризованный ключ или RID
), ядру пришлось бы сканировать все записи 1M
, чтобы определить, какую из них удалить.
Если бы вторичный ключ был UNIQUE
, значение column
было бы достаточно для уникального определения местоположения узла в индексе, поэтому сохранение указателя строки в узлах ветви не требуется (и именно поэтому они не сохраняются).
Эта дискуссия также может быть вам интересна:
http://www.sqlservercentral.com/Forums/Topic714684-1545-6.aspx
Обновление:
Для проверки содержимогоузлы ветвления, вы можете использовать DBCC IND
:
CREATE TABLE t_clustered (id INT NOT NULL PRIMARY KEY, nval INT, uval INT)
CREATE TABLE t_nonclustered (id INT NOT NULL PRIMARY KEY NONCLUSTERED, nval INT, uval INT)
CREATE INDEX ix_clustered_nval ON t_clustered (nval)
CREATE UNIQUE INDEX ux_clustered_uval ON t_clustered (uval)
CREATE INDEX ix_nonclustered_nval ON t_nonclustered (nval)
CREATE UNIQUE INDEX ux_nonclustered_nval ON t_nonclustered (uval)
;
WITH q(id) AS
(
SELECT 1
UNION ALL
SELECT id + 1
FROM q
WHERE id < 10000
)
INSERT
INTO t_clustered
SELECT id, (id - 1) / 10 + 1, id
FROM q
OPTION (MAXRECURSION 0)
;
WITH q(id) AS
(
SELECT 1
UNION ALL
SELECT id + 1
FROM q
WHERE id < 10000
)
INSERT
INTO t_nonclustered
SELECT id, (id - 1) / 10 + 1, id
FROM q
OPTION (MAXRECURSION 0)
-- Replace mydb with your database name
DBCC IND (mydb, t_clustered, -1)
DBCC IND (mydb, t_nonclustered, -1)
В выходных данных этих команд вы должны искать записи с PageType = 2
(страница индекса) и IndexLevel > 0
(неконечный узел) инайдите их PageID
.
В моем случае я получил следующие PageID
: 21074, 21076, 21105, 21107. Обратите внимание, что они специфичны для конкретного сайта: у вас будут другие значения.
Затем вы должны использовать DBCC PAGE
, чтобы просмотреть содержимое этих страниц:
DBCC PAGE (mydb, 1, 21074, 3)
DBCC PAGE (mydb, 1, 21076, 3)
DBCC PAGE (mydb, 1, 21105, 3)
DBCC PAGE (mydb, 1, 21107, 3)
FileId PageId Row Level ChildFileId ChildPageId nval (key) id (key) KeyHashValue
FileId PageId Row Level ChildFileId ChildPageId uval (key) KeyHashValue
FileId PageId Row Level ChildFileId ChildPageId nval (key) HEAP RID (key) KeyHashValue
FileId PageId Row Level ChildFileId ChildPageId uval (key) KeyHashValue
Wмы видим, что неконечные узлы неуникального вторичного индекса в nval
содержат указатели записей (id (PRIMARY KEY CLUSTERED)
и RID
, соответственно), в то время как узлы уникального индекса в uval
не содержат указателей записей,только значения в самом индексируемом столбце.
Это опять-таки, потому что при уникальном индексе значение индексируемого столбца достаточно, чтобы найти его узел в индексе, а при неуникальном индексе это не так..