Зачем добавлять ключи кластерного индекса ко всем (промежуточным) узлам в NCI? - PullRequest
0 голосов

Учитывая кластеризованную таблицу,
Quassnoi написал (последняя фраза в ответе):

Похоже, что кластерный ключ добавляется (ко всем) промежуточным узлам неуникального некластеризованного индекса.И по той же логике RID добавляются к промежуточным узлам в случае некластеризованной таблицы (?)

Какова цель этого?

Обновление:
В настоящее время этот вопрос имеет 9 голосов: -5, +4, началось с простого анонимного -3), правильный ответ противоречит большинству документов MSDN.
Его ценность не в самом деле, а в том, как решать подобные проблемы, связанные с внутренними компонентами SQL Server, которые либо противоречивы, либо неправильно, либо недостаточно описаны в документации.

Обновление 2: @ Quassnoi,
спасибо за ваш ответ, обогащая мои способности исследовать себя, не задавая глупых вопросов.

DBCC IND () не выводит PageID.Я не понял, что его PagePID вместо этого (из вывода DBCC IND) соответствует PageID в выводе DBCC DBCC Page ().
У меня есть еще вопросы по их использованию (и изучению / исследованию внутренних органов) или другим альтернативам.Я не уверен, почему этот тип вопросов рассматривается здесь как спам.
Можете ли вы посоветовать мне подходящие форумы / форумы для этого типа вопросов (по внутренним компонентам SQL Server)?

Ответы [ 2 ]

4 голосов
/ 30 октября 2010

Похоже, что кластерный ключ добавляется (ко всем) промежуточным узлам неуникального некластеризованного индекса.И по той же логике 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 не содержат указателей записей,только значения в самом индексируемом столбце.

Это опять-таки, потому что при уникальном индексе значение индексируемого столбца достаточно, чтобы найти его узел в индексе, а при неуникальном индексе это не так..

1 голос
/ 30 октября 2010

Вы задаете вопросы о том, что говорили другие, без какого-либо понимания предмета (ИТ; B-деревья; структуры индексов), о том, что они говорили, делали заявления.Это служба ответов, а не учебник.

"Похоже, что кластерный ключ добавляется (ко всем) промежуточным узлам неуникального некластеризованного индекса"

Нет.Quassnoi ничего не сказал в этом роде.Вы не можете принимать заявления (ответы в контексте; вопрос) и оценивать их изолированно.Ключ CI только применим к конечному уровню, а не к "промежуточным узлам".

"И по той же логике RID добавляются к промежуточным узлам в случае отсутствиякластеризованная таблица (?) "

Логика?Нет снова.Определение того, что хвост слона сделан из густых длинных волосков, не означает, что ствол также сделан из волос.

Задайте еще один вопрос о нелистовых узлах неуникального, не сгруппированногоиндекс.Я немного расстроился из-за этой проблемы.

Ответ.Для вашего теперь постоянно подтвержденного уровня понимания, некластеризованный индекс имеет полное значение кластеризованного ключа в качестве записи на уровне листа.Период.Конец истории.В этом нет ничего сложного, потому что (а) количество шагов одинаковое (б) индекс CI (не конечный) будет в любом случае находиться в кеше и, следовательно, очень быстро, без необходимости доступа к диску до последнего (конечного уровня).

Поиск ключа NCI, без CI: поиск индекса -> RID -> Поиск строки данных -> Строка данных

Поиск ключа NCI, с CI: Поиск индекса -> Ключ CI -> Поиск кластеризованного индекса-> Строка данных

Какова цель этого?

Производительность.Все поставщики понимают, что самым медленным компонентом в цепочке функций, активируемых запросом, является диск, единственный компонент с движущимися частями.Все они делают все возможное, чтобы избежать доступа к диску и повысить производительность.Сам индекс является самой основной структурой, позволяющей избежать доступа к диску, начиная с 1960-х годов.Базовое B-дерево с тех пор не изменилось, у него просто миллион крошечных улучшений.

Теперь проблема в том, что, хотя это правда, у каждого поставщика есть (а) свои собственные маленькие специальные приемы, которые улучшают(добавьте, без изменения базовой операции, как описано в моих постах к вам) операцию и (b) в мире MicroShifty, она постоянно меняется, потому что улучшения, ну, на самом деле, не являются улучшениями.Дело в том, что мучительно низкий уровень не имеет отношения к пониманию того, как работают индексы;или подходит ли CI или NCI для вашего конкретного использования;или преимущества / недостатки каждого из них.

Я уже определил, чтобы помочь вам, не ввязываться в более низкие уровни, пока вы не поймете основы, более высокие уровни ... если вы это сделаете, выпотеряется, и это будет препятствием для вашего намерения учиться.Как доказано здесь.Опять же.

...