我们有一个带有多个联接的查询,其中sql server 2016没有采用最佳路径,并且我们无法在没有提示的情况下说服它(我们不希望使用) 简化的问题如下:
表A(1200万行) 表B(类型表,5行) 表C(1200万行)
查询(简化说明)
SELECT
[A].[ID]
,[A].[DATE_CREATED]
,[A].[DATE_LAST_MODIFIED]
,[A].[CODE]
,[B].[CODE]
,[B].[DESCRIPTION]
,[C].[EVENT_ID]
,[C].[SOURCE_REFERENCE]
,[C].[EVTY_ID]
,[C].[BUSINESS_KEY]
,[C].[DATA]
,[C].[EVENT_DATE]
FROM A
JOIN B ON [B].[ID] = [A].[PSTY_ID] AND [B].[ACTIVE] = 1
JOIN C ON [C].[ID] = [B].[EVEN_ID] AND [C].[ACTIVE] = 1
WHERE [B].[CODE] = 'nopr' OR [B].[CODE] = 'inpr'
从B中选择的代码对应于值1和2
表A最多包含10个PSTY_ID值1或2,其余为3,4或5
从A.PSTY_ID到B.ID有一个外键
表A PSTY_ID 1,2上有一个过滤索引,所有选定的列都作为包含列
优化器似乎无法识别出我们试图选择值1和2,并且不使用索引或不以表B开头(尝试强制子查询或更改表顺序无济于事,仅提示OPTION( FORCE ORDER)可以说服优化器,但这是我们不想要的)
仅当我们在where子句中对B.ID或A.PSTY_ID值1和2进行硬编码时,优化器才从表B开始采用正确的路径。
如果我们不这样做,它将开始将表A与表C联接在一起,然后才与表B联接,从而导致处理时间大大增加(大约50倍)
我们还试图声明这些值并将其用作变量,但还是没有运气。
有人知道这是否是一个已知问题,或者可以解决该问题吗?
答案 0 :(得分:0)
在这种情况下,除非您在filtered index
子句中包含值1
和2
,否则将不会使用您的where
,即使您尝试加入,也无法更改它与仅在其行中具有1
,2
的表。
Filtered index
将永远不会基于某些“假设” 来使用某些表(物理的或派生的,例如CTE
或subquery
)的值实际上您的子查询没有帮助。
因此,如果要使用它,则应在查询中添加与过滤索引相同的where
条件。
由于您不想添加此条件,但仍想更改以B
表开头的表的连接顺序,因此可以使用temporary table
/ table variable
,如下所示:< / p>
select [ID]
,[CODE]
,[DESCRIPTION]
,[EVEN_ID]
into #tmp
from B
where ([CODE] = 'nopr' OR [CODE] = 'inpr') and [ACTIVE] = 1
现在在查询中使用此#tmp
代替B
。