sql server对执行计划没有最严格的限制

时间:2019-01-08 10:02:28

标签: sql sql-server

我们有一个带有多个联接的查询,其中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倍)

我们还试图声明这些值并将其用作变量,但还是没有运气。

有人知道这是否是一个已知问题,或者可以解决该问题吗?

1 个答案:

答案 0 :(得分:0)

在这种情况下,除非您在filtered index子句中包含值12,否则将不会使用您的where,即使您尝试加入,也无法更改它与仅在其行中具有12的表。

Filtered index永远不会基于某些“假设” 来使用某些表(物理的或派生的,例如CTEsubquery)的值实际上您的子查询没有帮助。 因此,如果要使用它,则应在查询中添加与过滤索引相同的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