2

这是带有CommonTableExpression的SQL。请注意,USERS_PROJECTS_CTE使用了两次。CTE在执行计划上的表现。显示两次还是两次?

WITH USERS_PROJECTS_CTE (PRO_ID, SHOW_IAS, USERNAME) 
    AS 
    (
     SELECT up.PRO_ID, up.SHOW_IAS, ISNULL(u.FIRST_NAME, '') + ' ' + ISNULL(u.SECOND_NAME, '') 
     FROM SFMIS07_PRO.USERS_PROJECTS up 
     INNER JOIN SFMIS07_ADM.USERS AS u 
       ON up.USER_ID = u.ID 
     WHERE up.IS_RESP_PERSON = 1 AND up.valid_to is null 
    ) 
    SELECT up.PRO_ID, 
      up1.USERNAME as RESP_USER1, 
      up2.USERNAME as RESP_USER2, 
      up.COUNT_ 
    FROM SFMIS07_PRO.PRO_RESP_USERS_KERNEL_MV AS up 
     LEFT JOIN USERS_PROJECTS_CTE AS up1 ON up.PRO_ID = up1.PRO_ID AND up1.SHOW_IAS=1 
     LEFT JOIN USERS_PROJECTS_CTE AS up2 ON up.PRO_ID = up2.PRO_ID AND up2.SHOW_IAS=0 

执行计划。需要注意的是CTE显示两次: enter image description here

问题:

  1. 我是正确的,CTE不仅显示两次,但两次处理?
  2. 是否可以通知QO重新使用CTE?
  3. QO原则上可以检测“相同的SQL片段”并重用结果(我想通过应对已经准备好的数据来实现这一点)?
  4. 如何优化查询(不使用时态表:) :)?

回答

4

我说得对,CTE不仅显示两次,而且是两次处理?

是否可以告知QO重用CTE?

不直接但也有一些黑客,以鼓励这个。

有可能是QO原则检测“相同的SQL片段” 和重用的结果(我想这个实现 - 通过应对 早已准备好的数据)?

原则上同意。有关示例,请参阅Microsoft Research Paper Efficient Exploitation of Similar Subexpressions for Query Processing

如何优化查询(不使用时态表:)?

最可靠的方法是使用临时(非时间)表。请参阅Provide a hint to force intermediate materialization of CTEs or derived tables以获得更多解决方法。

+0

你见过QO重复数据删除连接吗?我相信这个功能在2012年完全不存在。 – usr

+0

@usr - 是的,研究论文的内容到目前为止还没有进入到AFAIK的产品中。我只是回答“原则上”的一部分。目前,如果你想要中间实现并且不能自己明确地做,那么你需要采取诸如'TOP(2147483647)'hack之类的方式。 –

+0

只是为了追加:hack“Top 2147483647”不适用于自我连接(因为我不遵守原则) –