2015-10-06 150 views
2

我有以下的sql。当我检查这个查询的执行计划时,我们会观察索引扫描。我如何用索引查找来替换它。我在IdDeleted列上有非聚集索引。 Execution Plan性能调整SQL

SELECT Cast(Format(Sum(COALESCE(InstalledSubtotal, 0)), 'F') AS MONEY) AS TotalSoldNet, 
     BP.BoundProjectId            AS ProjectId 
FROM BoundProducts BP 
WHERE BP.IsDeleted=0 or BP.IsDeleted is null 
GROUP BY BP.BoundProjectId 

我试过这样并得到索引查找,但结果是错误的。

SELECT Cast(Format(Sum(COALESCE(InstalledSubtotal, 0)), 'F') AS MONEY) AS TotalSoldNet, 
     BP.BoundProjectId            AS ProjectId 
FROM BoundProducts BP 
WHERE BP.IsDeleted=0 
GROUP BY BP.BoundProjectId 

任何人都可以好心地建议我使用索引查找来获得正确的结果集。

我的意思是如何替换(BP.IsDeleted = 0或BP.IsDeleted为null)条件以利用索引查找。

编辑,添加的行数从其中一个答案的评论:

null: 254962 rows 
0: 392002 rows 
1:  50211 rows 
+0

我的索引定义有两列(BoundProjectId,IsDeleted)。我想将其更改为索引搜索而不是索引扫描。 – StackUser

+1

一种可能性是做两个查询,每个条件一个,和'UNION'他们在一起 – HoneyBadger

+1

@HoneyBadger可能不是最好的选择,因为你会扫描表两次。 –

回答

0

你尝试过一个UNION ALL? 选择... 请将isDeleted在哪里= 0 UNION ALL 选择... 请将isDeleted哪里是空

或者你可以添加一个查询提示(指数= [INDEXNAME])

也知道,基数将确定SQL是否使用搜索或扫描 - 搜索速度更快,但如果索引不覆盖所有需要的列,则可能需要密钥查找。一个好的经验法则是,如果查询将返回超过5%的表,那么SQL将更喜欢扫描。

+0

您的第一条建议将使查询按照@RaduGheorghiu在评论中提及的方式扫描表格两次。如果桌子很大,这对性能来说会很昂贵。 –

+1

我读过的帖子说这个经验法则只适用于10%或更多。另外,我读过的帖子说这个百分比没有“幻数”。我倾向于认为没有幻数,因为它将全部由查询**成本**确定。成本比*行数*更复杂。是的,基数很重要,但它不是唯一的因素。 –

+0

@John:我的桌子每天都在增长。目前该表格包含50万条记录。我预计大概有两三百万。 – StackUser

1

您没有获得索引查找,因为您正在获取表中几乎93%的行,并且在这种情况下,只是扫描整个索引更快,更便宜。

如果你有性能问题,你应该考虑移除format()函数,特别是当查询返回很多行时。阅读more from this blog post

其他选项可能是创建索引视图并预先汇总数据。这当然会增加更新/插入操作的开销,所以只有在这种情况经常发生时才会更新表的更新频率。