当表有不唯一的聚集索引时,非聚集索引指向什么?

var*_*ble 0 index sql-server

假设表有 name 和 id 列。

ID是唯一的非聚集索引。所以this指向堆表。

如果我将Name设置为聚集索引(非唯一),那么ID非聚集索引将指向什么?

我知道它不会指向堆,因为该表现在是聚集索引。

通常,非聚集索引指向聚集键,但在上述情况下,聚集键不是唯一的。那么ID(非聚集索引)指向什么呢?

Tib*_*szi 6

非聚集索引 (NC) 指向聚集索引 (CL) 键,即使 CL 索引不唯一。

当集群键中遇到重复项时,SQL Server 会添加唯一符。我认为经常被忽视的是,这个唯一符只是为重复项添加的。

如果您用完唯一符(集群键超过大约 40 亿个重复项),您会收到可怕的错误 666,并且您可能应该重新考虑集群键的选择:

The maximum system-generated unique value for a duplicate group was exceeded for index with partition ID %I64d. Dropping and re-creating the index may resolve this; otherwise, use another clustering key.
Run Code Online (Sandbox Code Playgroud)

下面的示例显示您无需为值的第一个实例支付 4 字节的惩罚:

--Table to play with
DROP TABLE IF EXISTS t
CREATE TABLE t(c1 char(3), c2 char(3))
CREATE CLUSTERED INDEX x ON t(c1)
GO

--Table to hold output from DBCC PAGE
DROP TABLE IF EXISTS dbccpage
CREATE TABLE dbccpage(ParentObject_ varchar(200), Object_ varchar(200), Field_ varchar(200), Value_ varchar(1000))
GO

INSERT INTO t VALUES('aaa', 'AAA'), ('aaa', 'A2A'), ('aaa', 'A3A'), ('bbb', 'BBB')

--This doesn't show enough details regarding uniqueifier
SELECT *
FROM t 
CROSS APPLY sys.fn_PhysLocCracker(%%physloc%%) AS f
CROSS APPLY sys.dm_db_page_info(DB_ID(), f.file_id, f.page_id, 'Detailed')

--DBCC PAGE to the rescue

--Get output to calling app
DBCC TRACEON(3604)
GO

DECLARE 
 @dbid int = Db_ID()
,@fileno int
,@pageno int
,@sql varchar(1000)

SELECT TOP(1) @fileno = f.file_id, @pageno = page_id
FROM t 
CROSS APPLY sys.fn_PhysLocCracker(%%physloc%%) AS f

SET @sql = CONCAT('DBCC PAGE(', @dbid, ', ', @fileno, ', ', CAST(@pageno AS varchar(10)), ', 1) WITH TABLERESULTS' )
PRINT @sql

INSERT INTO dbccpage
EXEC(@sql)

--Output:
SELECT Field_, Value_
FROM dbccpage
WHERE ParentObject_ LIKE 'DATA:' OR ParentObject_ like 'Slot%'
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


Han*_*dyD 5

当您在堆上构建非聚集索引时,索引的叶级节点存储用于在堆中定位数据行的行 ID (RID) 指针。RID 指向物理位置。它由文件标识符 (ID)、页码和页上的行号组成。

在唯一聚集索引中,叶级节点存储聚集索引键值来定位数据行,其方式与堆中的方式非常相似,唯一键值取代了 RID。

对于非唯一聚集索引,叶级节点存储聚集索引键值以及由数据库引擎生成和管理的唯一标识符,用于定位各个数据行。唯一标识符的长度为 4 个字节。

聚集索引键和唯一符的组合是唯一的,因此允许在进行键查找时定位数据行。

一些较旧的文档对此进行了介绍,但现在仍然有效。