Han*_*non 7 sql-server execution-plan database-internals sql-server-2012
采取以下再现:
USE tempdb;
IF OBJECT_ID(N'dbo.t', N'U') IS NOT NULL
DROP TABLE dbo.t
GO
CREATE TABLE dbo.t
(
id int NOT NULL
PRIMARY KEY
NONCLUSTERED
IDENTITY(1,1)
, col1 datetime NOT NULL
, col2 varchar(800) NOT NULL
, col3 tinyint NULL
, col4 sysname NULL
);
INSERT INTO dbo.t (
col1
, col2
, col3
, col4
)
SELECT TOP(100000)
CONVERT(datetime,
DATEADD(DAY, CONVERT(int, CRYPT_GEN_RANDOM(1)), '2000-01-01 00:00:00'))
, replicate('A', 800)
, sc2.bitpos
, CONVERT(sysname, CHAR(65 + CRYPT_GEN_RANDOM(1) % 26)
+ CHAR(65 + CRYPT_GEN_RANDOM(1) % 26)
+ CHAR(65 + CRYPT_GEN_RANDOM(1) % 26))
FROM sys.syscolumns sc
CROSS JOIN sys.syscolumns sc2;
Run Code Online (Sandbox Code Playgroud)
在这里,我将聚集索引添加到一组不唯一的列上,并且是典型的单列非聚集索引:
CREATE CLUSTERED INDEX t_cx
ON dbo.t (col1, col2, col3);
CREATE INDEX t_c1 ON dbo.t(col4);
Run Code Online (Sandbox Code Playgroud)
此查询强制 SQL Server 对聚集索引进行查找。请原谅使用索引提示,这是获得 repro 的最快方法:
SELECT id
, col1
, col2
, col3
FROM dbo.t aad WITH (INDEX = t_c1)
WHERE col4 = N'JSB'
AND col1 > N'2019-05-30 00:00:00';
Run Code Online (Sandbox Code Playgroud)
在实际的查询计划显示在非聚簇索引扫描输出列表一个不存在的列:
从表面上看,这表示非唯一聚集索引中使用的 uniqifier。是这样吗?像这样命名的列是否总是聚集索引 uniqifier?
从表面上看,这表示非唯一聚集索引中使用的 uniqifier。是这样吗?
是的。
这个索引扫描中这个 Uniq1002 列的目的是什么?
非聚集索引中的每一行都必须与基表中的一行正好相关联,以便书签查找(RID 或键)正常工作。此映射由“行定位器”提供。
对于堆表,行定位符是 RID。对于聚集行存储表,它是聚集键(必要时包括唯一符)。
要使计划中的Key Lookup起作用,它必须能够访问行定位器。这包括uniquifier,因此它必须由非聚集索引扫描发出。
所述唯一标志被存储在该行的可变长度部分,以便在需要的时候只占用空间(即,当重复的键实际存在)。
像这样命名的列总是聚集索引唯一符吗?
是的。uniquifier 列始终命名为UniqXXXX
。与堆表关联的行定位器名为BmkXXXX
。列存储表的行定位器名为ColStoreLocXXXX
。
可以在包含功能性query_trace_column_values
扩展事件的SQL Server 版本上直接观察 uniquifier 的值。
此未记录且不受支持的事件位于Debug通道中。它是在 SQL Server 2016 中引入的,并停止围绕 SQL Server 2017 的 CU11 工作。
例如:
CREATE TABLE #T (c1 integer NULL INDEX ic1 CLUSTERED, c2 integer NULL INDEX ic2 UNIQUE, c3 integer NULL);
GO
INSERT #T
(c1, c2, c3)
VALUES
(100, 101, 0),
(100, 102, 1),
(100, 103, 2);
GO
DBCC TRACEON (2486);
SET STATISTICS XML ON;
SELECT T.* FROM #T AS T WITH (INDEX(ic2));
SET STATISTICS XML OFF;
DBCC TRACEOFF (2486);
GO
DROP TABLE #T;
Run Code Online (Sandbox Code Playgroud)
有没有计划:
它在 SQL Server 2016 上产生如下事件输出: