繁体   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