[英]Clustered index key should be part of the non-clustered index key, but how can I see it?
在 SQL Server 中,當表上定義了聚簇索引時,聚簇索引鍵將作為“隱藏”鍵隱式添加到任何非聚簇索引中。 但是為什么這個“隱藏”的列沒有出現在元數據查詢中呢?
例如,如果我定義以下簡單表:
USE [tempdb];
DROP TABLE IF EXISTS abc;
CREATE TABLE abc (col1 INT NOT NULL, col2 INT NOT NULL, col3 INT);
ALTER TABLE [dbo].[abc] ADD CONSTRAINT PK_abc PRIMARY KEY CLUSTERED ([col1]);
CREATE NONCLUSTERED INDEX IX_2 ON [dbo].[abc] ([col3])
然后運行一個查詢來查看索引信息:
SELECT object_schema_name(t.object_ID)+'.'+t.name AS The_Table,
i.[name] AS The_Index,
i.[type_desc],
index_column_id,
col_name(Ic.Object_Id, Ic.Column_Id) AS The_Column --the column
FROM sys.tables t
INNER JOIN sys.indexes i
ON t.object_ID=i.object_ID
INNER JOIN sys.Index_columns ic
ON i.Object_ID=ic.Object_ID
AND i.index_ID=ic.index_ID
WHERE i.object_id = OBJECT_ID('dbo.abc') --<== filter by table if necessary
ORDER BY t.name,i.index_id, index_column_id;
我明白了:
The_Table The_Index type_desc index_column_id The_Column
------------ ------------ ---------------- --------------- -------------
dbo.abc PK_abc CLUSTERED 1 col1
dbo.abc IX_2 NONCLUSTERED 1 col3
因此很容易看出非聚集索引不包含“col1”,我希望將其包含在內,因為它是聚集索引鍵。
有沒有辦法看到這個列實際上是非聚集索引的一部分?
查看它的一種方法是從一個簡單的表中執行 SELECT 並查看它使用了哪些索引。
在下面的設置中,我有
(注意 - 我使用數字表來填充具有 10,000 行的臨時表)。
CREATE TABLE #Test (C1 int PRIMARY KEY NONCLUSTERED, C2 int, C3 int, C4 nvarchar(50));
CREATE CLUSTERED INDEX #CX_Test ON #Test (C2);
CREATE NONCLUSTERED INDEX #IX_Test ON #Test (C3);
-- Populate test with 10,000 rows
INSERT INTO #Test (C1, C2, C3, C4)
SELECT n, n, n, N'Text here to fill up space so more reads on data'
FROM dbo.Numbers
WHERE n <= 10000;
UPDATE STATISTICS #Test;
現在,運行SET STATISTICS TIME, IO ON;
並打開“包括實際執行計划”,然后執行以下操作
SELECT C3, C2
FROM #Test;
SELECT C3, C1
FROM #Test;
第一個 (SELECTING C3, C2) 僅對非聚集索引進行索引掃描 - #IX_Test - 顯示聚集列也包含在非聚集索引中。
另一方面,第二個 (SELECTING C3, C1) 執行聚簇索引掃描以獲取 C1 字段中所需的信息——盡管在本例中,它是主鍵。 但是,因為它不是非聚集索引的一部分,它必須從更笨重的聚集索引中獲取信息(相應地,邏輯讀取次數比第一個索引高 8 倍)。
最后,你可以做另一種測試
SELECT TOP 10 C3, C2
FROM #Test
ORDER BY C3;
SELECT TOP 10 C3, C1
FROM #Test
ORDER BY C3;
這些和上面類似,但是因為它只是用 ORDER BY C3 取 TOP 10,所以使用非聚集索引是有用的。
在第一個中,它只需要讀取非聚集索引,因為 C2 也包含在非聚集索引中。
在第二個中,它需要進行鍵查找以獲取 C1 數據,因為它不包含在非聚集索引中。
最后,如果我刪除聚集索引(所以現在表沒有聚集索引 - 它只是一個堆)並再次運行最后的語句
DROP INDEX #CX_Test ON #Test;
SELECT TOP 10 C3, C2
FROM #Test
ORDER BY C3;
SELECT TOP 10 C3, C1
FROM #Test
ORDER BY C3;
這些計划彼此相同——從非聚集索引讀取,然后執行 RID 查找(例如,使用 Row_ID 而不是聚集索引)以獲取其他字段。
刪除聚簇索引有效地改變了非聚簇索引的內容,但並沒有真正改變它的定義。
編輯:這是一個有點違反直覺的。 使用最初的索引(在刪除聚簇索引之前),運行以下命令。
SELECT C2
FROM #Test;
在這種情況下,它會從非聚集索引中進行讀取,即使在索引 (C3) 中實際指定的字段實際上並不在 SELECT 語句中。 SQL Server 簡單地問自己“我應該從聚簇索引(它有很多額外的讀取)或較小的非聚簇索引中獲取數據嗎?” - 並且顯然決定非集群是要走的路。
更新 - 數據方法
在評論中,OP 指定他們想要一種通過元數據的方法。
我一直無法獲得元數據方法,但我找到了一種可以使用 DBCC 直接查看實際數據的方法,這表明包含聚簇索引。
這是基於https://www.mssqltips.com/sqlservertip/1578/using-dbcc-page-to-examine-sql-server-table-and-index-data/ - 但請注意,您似乎不再需要設置跟蹤標志 3604。
為此,我將在數據庫Testdb
中創建一個新表TestTab
,其設置與上面類似(非聚集主鍵、單獨的聚集索引、一個用於非聚集索引的字段和另一個 misc 字段)。
CREATE TABLE TestTab (
TT_ID int PRIMARY KEY NONCLUSTERED,
TT_CX int,
TT_IX_field nvarchar(5),
TT_Other_field nvarchar(50)
);
CREATE CLUSTERED INDEX CX_TestTab ON TestTab (TT_CX);
CREATE NONCLUSTERED INDEX IX_TestTab ON TestTab (TT_IX_field);
INSERT INTO TestTab (TT_ID, TT_CX, TT_IX_Field, TT_Other_field) VALUES
(1, 15, 'DKTPE', 'Random text goes here'),
(2, 10, 'GEWPX', 'More random text');
現在,第一個命令是獲取相關頁面信息
DBCC IND('Testdb', TestTab, -1);
前 11 列如下(ObjectIDs 和 PartitionIDs 'X'ed out)
PageFID PagePID IAMFID IAMPID ObjectID IndexID PartitionNumber PartitionID iam_chain_type PageType IndexLevel
1 133075 NULL NULL XXXXXXX 1 1 XXXXX In-row data 10 NULL
1 152432 1 133075 XXXXXXX 1 1 XXXXX In-row data 1 0
1 133077 NULL NULL XXXXXXX 2 1 XXXXX In-row data 10 NULL
1 160528 1 133077 XXXXXXX 2 1 XXXXX In-row data 2 0
1 133078 NULL NULL XXXXXXX 3 1 XXXXX In-row data 10 NULL
1 169849 1 133078 XXXXXXX 3 1 XXXXX In-row data 2 0
從那里開始,最后一行是相關的(它是索引 3 的實際數據)。 第一列 (FileID) 是 1,第二列 (PageID) 是 169849 - 使用這些作為下一個 DBCC 命令的輸入(我相信最后一個值 3 代表詳細程度)。
DBCC PAGE('Testdb',1,169849,3) WITH TABLERESULTS;
這報告了兩個表——第二個表是索引的內容。 它顯示索引字段 (TT_IX_Field) 以及聚集索引值 (TT_CX)。
FileId PageId Row Level TT_IX_field (key) TT_CX (key) UNIQUIFIER (key) KeyHashValue Row Size
1 169849 0 0 DKTPE 15 0 (eba1206db4a9) 22
1 169849 1 0 GEWPX 10 0 (0d8521571a6a) 22
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.