为什么查询优化器在合并联接后使用排序?

时间:2018-10-11 13:21:11

标签: sql sql-server query-optimization sql-execution-plan

考虑此查询:

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上有一个半联接。

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

pt是带有PK(地图,pda,线)的交易明细表

Here's the execution plan

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

为什么会发生这种排序(或更准确地说:为什么此时尚未对数据进行排序)?查询优化器是否缺少“合并合并然后其输出(仍)按连接谓词排序”的逻辑?我想念什么吗?

2 个答案:

答案 0 :(得分:0)

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

问题是,内部合并联接(在EXCEPT之前)基于表dt,而不是基于pt。因此,结果行将与EXCEPT的另一边(基于pt的顺序不同)。

为什么SQL Server会这样做?不清楚。我会做不同的。也许统计数据没有更新。也许只有很少的行对策略没有太大影响。

答案 1 :(得分:0)

第一次合并的结果将按import timeit setup = ''' import pandas as pd import numpy as np def val(): v = np.random.normal(0, 0.2) return v if 0 <= v <= 1 else 0 def gen_sentence(fdf, s): return fdf.columns[np.random.random(len(fdf.columns)) < fdf.loc[s]] n = 500 m = 100 fdf = pd.DataFrame([[val() for _ in range(n)] for _ in range(m)]) fdf = fdf.join(pd.DataFrame({"s": [i for i in range(m)]})) fdf = fdf.set_index("s") fdf.columns = ["w%d" % i for i in range(n)] ''' test = "x = np.random.randint(0, m); gen_sentence(fdf, x)" print(timeit.timeit(test, setup=setup, number=5000)) 排序。但是,您自己提到了连接谓词,并且此第一次合并的连接谓词仅基于map, pda, line(它们是map, pda子句内部的谓词,除了exists包含下推至索引扫描)。输入所有首先 required 并按cancelledmap进行排序,因此,这是保证该数据唯一的排序顺序,就查询的其余部分而言有关。

但是,正如我们所知,第一次合并的输出实际上是由pda附加排序的输入得出的。看来优化器当前无法发现这种情况。优化的顺序可能意味着永远不可能意识到这种情况。因此,目前,它引入了额外的排序方式。