让我们有一个像这样创建的简单表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对于第1季度如此严重地估计结果大小(请参阅打印屏幕)。查询计划中的大多数运算符都是精确估计的,但是,从根本上说,哈希匹配运算符会引入完全疯狂的猜测。
为了使它更有趣,我尝试对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的查询计划更有效。
所以问题是:为什么对Q1的估计是不正确的,而对Q2的估计却是精确的?请不要发布此SQL的其他重写(我知道即使这样也可以写没有子查询),我只对选择性估计器行为的解释感兴趣。谢谢。
答案 0 :(得分:3)
它无法识别出orderby
的值对于具有相同groupby
的所有行都是相同的,因此它认为distinct groupby, orderby
的组合将不仅仅是distinct groupby
。
它将DISTINCT orderby
的估算值(对我来说是35.0367
)和DISTINCT groupby
的估算值(对我来说就是100
)相乘,就好像它们是不相关的。
我获得了Q1中根节点的3503.67
估算值
此重写避免了它,因为它现在仅按单个groupby
列进行分组。
SELECT groupby,
max(orderby) AS orderby
FROM (SELECT g1.groupby,
(SELECT count(*)
FROM tt g2
WHERE local_search = 1
AND g1.groupby = g2.groupby) AS orderby
FROM tt g1) d
GROUP BY groupby
OPTION(maxdop 1)
尽管您的第2季度表明,但这不是查询的最佳方法,并且注释@GarethD使得多次运行相关子查询并丢弃重复项的效率低下。