我有一个临时表#termin,其中包含 3 行
当我执行以下查询时
SELECT t.termin, ttw.tourid, twt.va_nummer_int
FROM #term AS t
INNER JOIN plinfo.t_touren_werbeflaechentermine AS ttw
ON ttw.termin = t.termin
INNER JOIN wtv.t_werbeflaechentermine AS twt
ON twt.jahr = t.jahr
AND twt.termin = t.termin
AND twt.ID_Wt = ttw.id_wt
GROUP BY t.termin, ttw.tourid, twt.va_nummer_int
每个表都使用匹配的索引连接。两个表都由 ps_termin(termin) 分区。
对于第一个表 (t_touren_werbeflaechentermine),它会进行分区消除并只读取行的一个子集,而对于第二个表 (t_werbeflaechentermine),它会扫描整个索引 ( jahr, termin, id_wt include (va_nummer_int)
)。
所以我的问题是:为什么它是索引扫描(而不是搜索),为什么它不消除第二个表的分区。
PS:在WITH (FORCESEEK)
第二个表上使用时,它会在执行计划中切换两个表,并对第一个表进行全索引扫描...
PPS:执行计划可以在这里找到
为什么要进行索引扫描?
与 loop-seek 方法相比,SQL Server 估计扫描数据的成本可能更低(只有 1.7MM 行,因此是一个相对较小的表)。
扫描
t_werbeflaechentermine
表将处理所有1,708,658
行,您的计划表明这会执行7,347 logical reads
。估计执行循环搜索
~70K seeks
(循环外侧的基数估计)。如果我们假设一次搜索是二分搜索,那么我们可能会估计这将具有70109.4 * LOG(1708658,2)
或的复杂度1,451,575
。这比扫描处理的行数略低
1,708,658
,但逻辑读取的数量会高得多,因为每个(估计的)~70K 搜索将执行几次逻辑读取,产生比选择的扫描更多的逻辑读取。这可能是循环搜索计划产生更高的估计成本并且未被选中的原因。无需扫描即可查看计划
如果您想将此计划与对两个连接都使用循环搜索的执行计划进行比较,您可以尝试将
OPTION (LOOP JOIN)
查询提示添加到您的查询中,以便两个连接都使用循环连接。发布此实际执行计划以进行比较将是有益的。为什么不消除分区?
我相信不会发生分区消除,
t_werbeflaechentermine
因为 SQL Server 没有哈希连接算法,该算法根据在哈希连接的构建端观察到的分区执行分区消除。在某些情况下,这将是一个很好的优化,但据我所知,在当前优化器中不可用:分区消除可用于循环连接的内侧,但不适用于散列连接的探测侧(除非查询包含分区列上的显式谓词)。为了进一步阅读,SQL Server 确实具有并置联接的概念,其中散列联接独立应用于以相同方式分区的两个表的每个分区。但是,此优化仅适用于 2 路连接,因此您的查询不符合条件。Paul White 在改进分区表连接性能中更详细地描述了这个和其他分区表连接注意事项。