Sql-Server
這個索引掃描中這個 Uniq1002 列的目的是什麼?
進行以下複製:
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;
在這裡,我將聚集索引添加到一組不唯一的列上,並且是典型的單列非聚集索引:
CREATE CLUSTERED INDEX t_cx ON dbo.t (col1, col2, col3); CREATE INDEX t_c1 ON dbo.t(col4);
此查詢強制 SQL Server 查找聚集索引。請原諒使用索引提示,這是獲得重現的最快方法:
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';
實際查詢計劃在非聚集索引掃描的輸出列表中顯示一個不存在的列:
從表面上看,這表示在非唯一聚集索引中使用的唯一標識符。是這樣嗎?像這樣命名的列是否總是聚集索引 uniqifier?
從表面上看,這表示在非唯一聚集索引中使用的唯一標識符。是這樣嗎?
是的。
這個索引掃描中這個 Uniq1002 列的目的是什麼?
非聚集索引中的每一行必須與基表中的一行恰好相關聯,這樣書籤查找(RID 或鍵)才能正常工作。此映射由“行定位器”提供。
對於堆表,行定位器是 RID。對於集群行儲存表,它是集群鍵(包括必要的唯一性)。
要使計劃中的Key Lookup起作用,它必須有權訪問行定位器。這包括uniquifier,因此它必須由非聚集索引掃描發出。
uniquifier儲存在行的可變長度部分中,因此它只在需要時(即實際存在重複鍵時)佔用空間。
像這樣命名的列是否總是聚集索引唯一標識符?
是的。uniquifier 列始終命名為
UniqXXXX
。與堆表關聯的行定位器名為BmkXXXX
。列儲存表的行定位器名為ColStoreLocXXXX
。觀察唯一性
可以在包含功能
query_trace_column_values
擴展事件的 SQL Server 版本上直接觀察 uniquifier 的值。此未記錄且不受支持的事件位於調試通道中。它是在 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;
有計劃:
它在 SQL Server 2016 上產生如下事件輸出: