为啥查询优化器在合并连接后使用排序?

Posted

技术标签:

【中文标题】为啥查询优化器在合并连接后使用排序?【英文标题】:Why does the query optimizer use sort after merge join?为什么查询优化器在合并连接后使用排序? 【发布时间】:2018-10-11 13:21:10 【问题描述】:

考虑这个查询:

select
    map,line,pda,item,qty,qty_gift,pricelist,price,linevalue,vat,
    vat_value,disc_perc,disc_value,dt_disc_value,netvalue,imp_qty,
    imp_value,exp_qty,exp_value,price1,price2,price3,price4,
    justification,notes
  from appnameV2_Developer.dbo.pt
  where exists (select 1 from [dbo].[dt] dt 
                where pt.map=dt.map and dt.pda=pt.pda and dt.canceled=0)
except
select 
    map,line,pda,item,qty,qty_gift,pricelist,price,linevalue,vat,
    vat_value,disc_perc,disc_value,dt_disc_value,netvalue,imp_qty,
    imp_value,exp_qty,exp_value,price1,price2,price3,price4,
    justification,notes
  from appnameV2_Developer_reporting.dbo.pt

我这样做是为了确保复制发布者数据库 (appnameV2_Developer) 与其订阅者数据库 (appnameV2_Developer_reporting) 之间的同一个表 (pt) 中没有数据差异。具体的复制文章在dt上有一个semijoin。

dt是带有PK(map,pda)的事务头表

pt是带有PK(map,pda,line)的交易明细表

Here's the execution plan

所以,我们有一个 Right Semi Join 合并连接。我希望它的结果按 (map,pda,line) 排序。但是随后,调用了 (map,pda,line) 上的排序运算符。

为什么会发生这种排序(或者更准确地说:为什么数据尚未按该点排序)?查询优化器是否缺少“当合并连接时,其输出(仍然)按连接谓词排序”的逻辑?我错过了什么吗?

【问题讨论】:

嗯,数据原来是按map、line、pda排序的,排序操作顺序是按map、pda、line我想的。有趣的问题。 【参考方案1】:

因为它决定使用“Merge Join”来执行EXCEPT 子句。为了执行 Merge Join,两个数据集必须具有相同的顺序。

问题是,内部 Merge Join(在 EXCEPT 之前)基于表 dt,而不是 pt。因此,结果行的顺序与EXCEPT 的另一侧不同,即基于pt

为什么 SQL Server 会这样做?不清楚。我会做不同的。也许统计数据没有更新。也许有少量行的策略并不重要。

【讨论】:

他们询问发生在两个合并之间的排序,其中第一个合并的一个输入也是第二个合并的另一个输入。鉴于合并需要排序的输入并且应该以相同的顺序发出行,他们会问为什么需要中间排序操作。 @Damien_The_Unbeliever 因为它们的顺序不同。一个基于dt,第二个基于pt Merge 要求 both 输入以相同的顺序排序。两个合并都使用pt @Damien_The_Unbeliever “两个合并都在使用 pt”——不正确。看执行计划。与我的预期相反(你也是),SQL Server 将其颠倒过来。你看到那里的“右半连接”了吗?我期待一个“左半加入”。 我在看执行计划。我们一定是在以某种方式谈论不同的目的,但我不确定如何。该计划包括 3 个聚集索引扫描,这些扫描直接馈送到合并中。其中两个扫描针对同一张表。合并要求两个输入以相同的方式排序。因此,在没有对 那些 输入进行排序的情况下,我们无论如何都可以得出结论,dtpt 具有相同的排序。【参考方案2】:

第一次合并的结果将按map, pda, line 排序。但是,您自己提到了连接谓词,并且第一次合并的连接谓词仅基于 map, pda (它们是 exists 子句中的谓词,除了 cancelled 已被下推到索引扫描)。第一次合并需要的所有输入都是按mappda 排序的,因此就查询的其余部分而言,这是该数据上唯一保证的排序顺序。 p>

但正如我们所知,第一次合并的输出实际上是从另外按line 排序的输入派生的。看来优化器目前无法发现这种情况。优化的顺序可能意味着它不可能识别出这种情况。所以目前,它引入了额外的排序。

【讨论】:

我不清楚你想用你的 1-note 表达什么。你想让我把计划粘贴到别的地方吗?或者回答一系列问题?对我来说没问题。 @GeorgeMenoutis - 我是说我实际上无法看到 pastetheplan 上的每个节点应用了哪些谓词,而使用 SSMS 中的实际计划,当我将鼠标悬停在上方时,我可以看到该信息他们 - 但我不确定这是我的问题还是工具的问题。所以它更像是“我坚信我在这里所说的是真实的,但缺乏自己验证的方法”。 我不是阅读计划的专家,但 pastetheplan 的 xml 部分不应该包含您可以在更有用的环境中查看的所有信息吗? 是的,你是对的。我之前没有注意到 XML 选项卡 :-)

以上是关于为啥查询优化器在合并连接后使用排序?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL高级第八篇:关联查询子查询和排序相关优化

数据库(比如MYSQL) ,表连结查询与子查询哪个效率高些? 为啥

MySQL 索引优化与子查询与左连接

Oracle 12.2:优化器在末尾添加 FOR UPDATE OF ... 块时更改 SELECT 查询的解释计划

优化查询 数据库优化

23.Mysql应用优化