J.D*_*.D. 2 performance sql-server clustered-index nonclustered-index bookmark-lookup performance-tuning
非聚集索引使用聚集索引的键定位行与该表没有聚集索引且非聚集索引通过 RID 定位行之间是否存在性能差异?
不同级别的碎片是否也会影响这种性能比较?(例如,在这两种情况下,表的碎片率为 0%、50%、100%。)
撇开碎片化的魔眼(在进行单例查找时并不重要),主要区别在于 RID 指定行所在的确切页面,而使用键查找则遍历聚集索引的非叶级别找到目标页面。Aaron Bertrand 在RID Lookup 是否比 Key Lookup 更快?中对此做了一些测试。
但是,堆可以在其中转发提取(或记录),在这种情况下,需要多个逻辑 IO 才能找到目标行。
我最近写了一篇关于这个的博客,我在这里复制内容以避免评论答案。
CREATE TABLE el_heapo
(
id INT IDENTITY,
date_fudge DATE,
stuffing VARCHAR(3000)
);
INSERT dbo.el_heapo WITH (TABLOCKX)
( date_fudge, stuffing )
SELECT DATEADD(HOUR, x.n, GETDATE()), REPLICATE('a', 1000)
FROM (
SELECT TOP (1000 * 1000)
ROW_NUMBER() OVER (ORDER BY @@SPID)
FROM sys.messages AS m
CROSS JOIN sys.messages AS m2
) AS x (n)
CREATE NONCLUSTERED INDEX ix_heapo ON dbo.el_heapo (date_fudge);
Run Code Online (Sandbox Code Playgroud)
我们可以用sp_BlitzIndex查看表
EXEC master.dbo.sp_BlitzIndex @DatabaseName = N'Crap',
@SchemaName = 'dbo',
@TableName = 'el_heapo';
Run Code Online (Sandbox Code Playgroud)
此查询将生成书签查找。
SELECT *
FROM dbo.el_heapo AS eh
WHERE eh.date_fudge BETWEEN '2018-09-01' AND '2019-09-01'
AND 1 = (SELECT 1)
OPTION(MAXDOP 1);
Run Code Online (Sandbox Code Playgroud)
现在我们可以导致一些转发的记录发生:
UPDATE eh
SET eh.stuffing = REPLICATE('z', 3000)
FROM dbo.el_heapo AS eh
WHERE eh.date_fudge BETWEEN '2018-09-01' AND '2019-09-01'
OPTION(MAXDOP 1)
Run Code Online (Sandbox Code Playgroud)
BlitzIndex 将向我们展示它们:
如果我们重新运行查找查询:
Profiler 也会显示不同之处: