【问题标题】:SQL Query takes a long time when filtering recent rows过滤最近的行时 SQL 查询需要很长时间
【发布时间】:2019-01-22 20:22:35
【问题描述】:

我有这个 SQL 查询,但我发现它最多可能需要 11 秒才能运行。我真的很困惑,因为当我将日期选择更改为 2018 日期时,它会立即返回。

这是查询:

select
    cv.table3ID, dm.Column1 ,dm.Column2, mm.Column1, 
    convert(varchar, cv.Date, 107) as Date, 
    mm.table2ID, dm.table1ID, mm.Column2,
    count(ctt.table4ID) as Total
from
    table1 dm
inner join 
    table2 mm on mm.table2ID = dm.table1ID
inner join 
    table3 cv on cv.table3ID = mm.table2ID
left join 
    table4 ct on ct.table4CVID = cv.table3ID
inner join 
    table4 ctt on ctt.table4MMID = mm.table2ID
where
    ctt.table4Date >= '2019-01-19'
    and ct.table4CVID is null  
    and dm.Column1 like '%Albert%'
    and cv.Column1 = 39505 
    and cv.Status = 'A'  
group by
    cv.table3ID, dm.Column1 ,dm.Column2, mm.Column1, 
    cv.Date, mm.table2ID, dm.table1ID, mm.Column2

我发现当我使用 ctt.table4Date >= '2018-01-19' 执行该查询时,会立即得到响应。但是对于“2019-01-19”,它需要 11 秒。

最初,当我发现查询需要 11 秒时,我认为这一定是索引问题,但我不确定它是否与索引有关,因为它在较旧的日期执行得很好。

我查看了具有不同日期的查询的执行计划,它们看起来完全不同。

对为什么会发生这种情况有任何想法吗?跟更新统计有关系吗?

[更新]

下图是table4 ctt在2018年和2019年的执行计划对比。根据执行计划,2018年占运营商成本的43%,2019年占45%。 Execution Plan comparison of table4 ctt 2019 and 2018. Top is 2019, bottom is 208

这里的图是table4作为ct的执行计划再次对比。同样在这里,顶部是 2019 年,底部是 2018 年。 Execution plan of table4 ct comparison 2019 and 2018. Top is 2019, bottom is 208

[更新 2]

以下是 SQL 执行计划:

当使用“2018-01-19”作为日期时:https://www.brentozar.com/pastetheplan/?id=SyUh8xXQV

当使用“2019-01-19”作为日期时:https://www.brentozar.com/pastetheplan/?id=rkELW1Q7V

【问题讨论】:

  • 请分享'2019-01-19'的执行计划
  • @MuhammadWaheed 整个计划?我无法添加整个计划。太长了。
  • 我看到的第一件事是一些图片中的实际行和估计行非常不同。这通常是由于过时的统计数据。您没有提及此表中有多少行,更新频率,特别是最近日期通常会添加新行吗?
  • @MuhammadWaheed 这是计划:brentozar.com/pastetheplan/?id=rkELW1Q7V

标签: sql sql-server query-tuning


【解决方案1】:

问题很可能是从其他表返回的行更多。您与 [update] 链接的聚集索引扫描仅显示聚集索引搜索。

但是,您确实需要意识到调用索引查找的次数是 144 次。实际读取的行数是 8 位,这会导致响应缓慢。

我猜当这对你来说很好时,这张桌子上的实际执行次数将是 1。144 在这里杀死你;鉴于穷人寻求谓词。如果您知道适合您的查询计划,并且已经存在索引来支持它,您应该强制搜索计划并给出明确的提示以按特定顺序加入。

编辑

查看共享计划,将日期更改为 2018 年对您来说更快,因为考虑到正在处理的数据量,SQL 切换到使用哈希匹配代替循环连接。

【讨论】:

  • 您好,感谢您的意见。我明白你在说什么,但我遇到的问题是,当我将条件日期更改为“2018-01-19”时,执行次数仅为 2,实际行数仅为 18。这是该日期的执行计划:brentozar.com/pastetheplan/?id=SyUh8xXQV
  • 好吧,这里的原因就是HashMatch了。当您查询 2018 年的行数时,SQL 决定执行 HashMatch 而不是循环连接。您可以要求提示引擎始终这样做,也可以通过明确地说 Table1 INNER LOOP JOIN Table2 .... 并强制搜索正确的索引来修复查询中的连接顺序。
  • 请注意,HashMatch 占用更多 CPU 资源。如果哈希匹配更适合您,您应该记住,运行查询最终会占用更多 CPU。
  • 谢谢@divyanshm 我强制使用table4 作为ctt 进行循环连接,这使得查询立即返回!但是我还是不明白为什么2019年的数据比2018年的数据多。
  • 2018年SQL估计你正在阅读的实际数据更多;因此它强制进行哈希匹配,因为这是连接两个大表的最快方法。 SQL 引擎认为使用日期 2019 进行查询时循环连接更快;因此它尝试循环连接(对于顶行中的每一行,从底部表中检索行)并且您的搜索谓词不够精确,无法仅返回您需要的行。
猜你喜欢
  • 2016-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多