pme*_*yer 3 sql-server performance
我有一个[Documents]包含以下列的表:
Name (string)
Status (string)
DateCreated [datetime]
Run Code Online (Sandbox Code Playgroud)
该表有大约100万条记录.这三列中的所有三列都有一个索引(每个列都有一个索引).
当我运行此查询时:
select top 50 *
from [Documents]
where (Name = 'None' OR Name is null OR Name = '')
and Status = 'New';
Run Code Online (Sandbox Code Playgroud)
执行速度非常快(300毫秒)
如果我运行相同的查询,但使用该ORDER BY子句,它真的很慢(3000毫秒)
select top 50 *
from [Documents]
where (Name = 'None' OR Name is null OR Name = '')
and Status = 'New'
order by DateCreated;
Run Code Online (Sandbox Code Playgroud)
我理解它在另一个索引(DateCreated)中搜索,但它应该真的慢得多吗?如果是这样,为什么?我能做些什么来加速这个查询(复合索引)?
谢谢
顺便说一句:所有索引都包含DateCreated了非常低的碎片,实际上我进行了重组并且它没有改变任何东西.
至于查询速度较慢的原因,查询需要"按顺序"返回行,因此需要进行排序,或者需要使用索引.
使用带有CreatedDate前导列的索引,SQL Server可以避免排序.但SQL Server还必须访问基础表中的页面以评估是否要返回该行,查看Status和Name列中的值.
如果优化器选择不使用CreatedDate作为前导列的索引,则需要首先找到满足谓词的所有行,然后执行排序操作以按顺序获取这些行.然后它可以从排序集返回前五十行.(SQL Server不一定需要对整个集合进行排序,但它需要遍历整个集合,并进行足够的排序以确保它具有需要返回的"前50个".
注意:我怀疑你已经知道这一点,但要澄清一下:SQL Server尊重ORDER BY之前的TOP 50.如果您希望任何50行满足谓词,但不一定是具有最低值DateCreated的50行,您可以重构/重写查询,获取(最多)50行,然后执行那些排序.
一些提高性能的想法
添加复合索引(如其他答案所示)可能会提供一些改进,例如:
ON Documents (Status, DateCreated, Name)
Run Code Online (Sandbox Code Playgroud)
SQL Server可能能够使用该索引来满足Status上的等式谓词,并且还可以在没有排序操作的情况下以DateCreated顺序返回行.SQL服务器也可以从索引中满足Name上的谓词,限制基础表中页面的查找次数,它需要为返回的行执行,以获取行的"所有"列.
对于SQL Server 2008或更高版本,我会考虑过滤索引...取决于Status ='New'的基数(即,如果满足谓词的行Status='New'是表的相对较小的子集.
CREATE NONCLUSTERED INDEX Documents_FIX
ON Documents (Status, DateCreated, Name)
WHERE Status = 'New'
Run Code Online (Sandbox Code Playgroud)
我还会修改要指定的查询 ORDER BY Status, DateCreated, Name
为了使order by子句与索引匹配,它并不真正改变返回行的顺序.
作为一个更复杂的替代方案,我会考虑添加一个持久计算列并在其上添加一个过滤索引
ALTER TABLE Documents
ADD new_none_date_created AS
CASE
WHEN Status = 'New' AND COALESCE(Name,'') IN ('','None') THEN DateCreated
ELSE NULL
END
PERSISTED
;
CREATE NONCLUSTERED INDEX Documents_FIXP
ON Documents (new_none_date_created)
WHERE new_none_date_created IS NOT NULL
;
Run Code Online (Sandbox Code Playgroud)
然后可以重写查询:
SELECT TOP 50 *
FROM Documents
WHERE new_none_date_created IS NOT NULL
ORDER BY new_none_date_created
;
Run Code Online (Sandbox Code Playgroud)