簡體   English   中英

聚簇索引鍵應該是非聚簇索引鍵的一部分,但是我怎么看呢?

[英]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 並查看它使用了哪些索引。

在下面的設置中,我有

  • C1 作為主鍵,但非集群
  • C2 作為聚簇索引,
  • C3 作為具有非聚集索引的列
  • C4 是一個只占用一些空間的列(使聚簇索引更加笨拙)

(注意 - 我使用數字表來填充具有 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM