【发布时间】:2018-12-20 13:29:22
【问题描述】:
让我们有一个像这样创建的简单表tt
WITH x AS (SELECT n FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) v(n)), t1 AS
(
SELECT ones.n + 10 * tens.n + 100 * hundreds.n + 1000 * thousands.n + 10000 * tenthousands.n as id
FROM x ones, x tens, x hundreds, x thousands, x tenthousands, x hundredthousands
)
SELECT id,
id % 100 groupby,
row_number() over (partition by id % 100 order by id) orderby,
row_number() over (partition by id % 100 order by id) / (id % 100 + 1) local_search
INTO tt
FROM t1
我有一个简单的问题 Q1:
select distinct g1.groupby,
(select count(*) from tt g2
where local_search = 1 and g1.groupby = g2.groupby) as orderby
from tt g1
option(maxdop 1)
我想知道为什么 SQL Server 对第一季度的结果大小估计如此糟糕(请参阅打印屏幕)。查询计划中的大多数运算符都是精确估计的,但是,在根哈希匹配运算符引入了完全疯狂的猜测。
为了让它更有趣,我尝试了对 Q1 的不同重写。如果我应用子查询的去相关,我会得到一个等效的查询 Q2:
select main.groupby,
coalesce(sub1.orderby,0) orderby
from
(
select distinct g1.groupby
from tt g1
) main
left join
(
select groupby, count(*) orderby
from tt g2
where local_search = 1
group by groupby
) sub1 on sub1.groupby = main.groupby
option(maxdop 1)
这个查询在两个方面很有趣:(1)估计准确(见打印屏幕),(2)它也有不同的查询计划,比第一季度的查询计划效率更高。
所以问题是:为什么 Q1 的估计是不正确的,而 Q2 的估计是精确的? 请不要发布此 SQL 的其他重写(我知道即使没有子查询),我只对选择性估计器行为的解释感兴趣。谢谢。
【问题讨论】:
-
您在第二个查询中获得更有效计划的原因是您执行
DISTINCT操作时。在第一个中,SQL Server 将首先评估所有行的子查询,然后删除重复项,在第二个中,首先删除重复项,然后每个groupby的值对子查询进行一次评估。如果您在第一个查询中使用GROUP BY groupby并删除DISTINCT,那么您将获得与第二个查询相同的计划。 -
@GarethD 嘿,SQL 是声明性语言,对吧? ;)
-
另外一个有趣的事情是 PostgreSQL 可以精确地估计结果,但是它的查询计划很糟糕。 Oracle 也正确估计了它。
标签: sql sql-server sql-server-2016 estimation