我有一个基于 col1 int 分区的分区表。我还有一个覆盖索引,用于我正在尝试排除故障的查询。
https://www.brentozar.com/pastetheplan/?id=BkNrNdgHm
以上是方案
随心所欲,SQL Server 决定对整个表进行聚簇索引扫描,这显然很慢。如果我强制使用索引(如上面的计划),查询将快速运行。
SQL Server用什么神奇的逻辑来决定覆盖索引没有用?我不确定 top/orderby 和 rowgoal 是否与它有任何关系。
我的表结构是
Create table object2(col1 int, col3 datetime, col4 int, col5, col6 etc) clusterd on col1
nonclustered non aligned index is on col3,col4 (col1 is clustered so its included in nonclust)
SELECT top(?) Object1.Column1
FROM Object2 Object1 WITH (NOLOCK,index(Column2))
WHERE Object1.Column3 >= ?
AND Object1.Column4 IN (?)
ORDER BY Object1.Column1
编辑添加的回购
CREATE PARTITION FUNCTION [PFtest](int) AS RANGE RIGHT FOR VALUES (100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000)
GO
CREATE PARTITION SCHEME [PStest] AS PARTITION [PFtest] all TO ([PRIMARY]);
GO
create table test([ID] [int] IDENTITY(1,1) NOT NULL primary key clustered,[Created] [datetime] NULL,[Type] [int] NULL,text1 varchar(10),text2 varchar(20))
on pstest(id)
set nocount on
declare @a int =1
declare @type int
while 1=1
begin
if @a%30 =0
insert into test (Created, Type, text1, text2) select getdate(),4,'four','four'
else
insert into test (Created, Type, text1, text2) select getdate(),1,'one','one'
set @a=@a+1
end
create nonclustered index ncl1 on test(created, type)
select min(created),max(created) from test
--2018-08-02 22:46:40.187 2018-08-02 22:49:01.577
SELECT top(10) ID
FROM test
WHERE Created >= '2018-08-02 22:49:01'
AND Type IN (1, 4)
ORDER BY ID -- clustered index scan
SELECT top(10) ID
FROM test
WHERE Created >= '2018-08-02 22:49:01.577'
AND Type IN (1, 4)
ORDER BY ID-- index seek of ncl1
是的,这很可能是行目标问题。
SQL Server 评估扫描聚簇索引(以避免排序)
?
比在非聚簇索引中搜索匹配项、排序这些匹配项,然后返回顶部匹配项更快地找到第一个匹配项(此时扫描将停止)?
。OPTION (QUERYTRACEON 4138)
在您的 SQL Server 版本上,您可以通过运行查询以禁用行目标来测试设置行目标是否是原因。相关问答:
一般来说,最基本的术语是,如果成本
Index scan
小于,Index Seek
则优化器可能会决定Index Scan
。在这种情况下,有很多记录大于
'2018-08-02 22:49:01'
并且只需要 10 条记录。所以如果优化器要从索引中检索记录,那么成本会更高。
所以它
Index Scan
和这个“找到足够好的计划”这里有非常少的记录大于
'2018-08-02 22:49:01.577'
所以在这 10 条记录中是 Optimiser 想要的Index Seek
。在这里您会注意到 Index Seek 运算符返回所有大于
'2018-08-02 22:49:01.577'
的行。实际行数是所有符合条件大于的行'2018-08-02 22:49:01.577'
。然后排序运算符将其切片为 10。因此它可能不是“找到足够好的计划”。