Sql-Server

這個索引掃描中這個 Uniq1002 列的目的是什麼?

  • June 1, 2019

進行以下複製:

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 上產生如下事件輸出:

事件輸出

引用自:https://dba.stackexchange.com/questions/239487