简单查询的选择性估计错误
Selectivity estimation error on a simple query
让我们创建一个简单的 table 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 服务器估计 Q1 的结果大小如此糟糕(参见打印屏幕)。查询计划中的大多数运算符都是精确估计的,但是,在根哈希匹配运算符中引入了完全疯狂的猜测。
为了让它更有趣,我尝试了对 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的估计是准确的?请不要post其他改写这个SQL(我知道即使没有子查询也可以写成),我只对选择性估计器行为的解释感兴趣。谢谢。
它无法识别具有相同 groupby
的所有行的 orderby
值都是相同的,因此它认为 distinct groupby, orderby
将具有比 [=14= 更多的组合].
它将 DISTINCT orderby
的估计值(对我来说是 35.0367
)和 DISTINCT groupby
的估计值(对我来说是 100
)相乘,就好像它们是不相关。
我得到了第 1 季度根节点 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)
这不是此查询的最佳方法,尽管如您的 Q2 所示,评论 @GarethD 使 运行 多次关联子查询并丢弃重复项的效率低下。
让我们创建一个简单的 table 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 服务器估计 Q1 的结果大小如此糟糕(参见打印屏幕)。查询计划中的大多数运算符都是精确估计的,但是,在根哈希匹配运算符中引入了完全疯狂的猜测。
为了让它更有趣,我尝试了对 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的估计是准确的?请不要post其他改写这个SQL(我知道即使没有子查询也可以写成),我只对选择性估计器行为的解释感兴趣。谢谢。
它无法识别具有相同 groupby
的所有行的 orderby
值都是相同的,因此它认为 distinct groupby, orderby
将具有比 [=14= 更多的组合].
它将 DISTINCT orderby
的估计值(对我来说是 35.0367
)和 DISTINCT groupby
的估计值(对我来说是 100
)相乘,就好像它们是不相关。
我得到了第 1 季度根节点 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)
这不是此查询的最佳方法,尽管如您的 Q2 所示,评论 @GarethD 使 运行 多次关联子查询并丢弃重复项的效率低下。