2

如何重写此 T-SQL 代码以产生相同的结果

   SELECT   ACC.Title,
            ACC.AdvertiserHierarchyId,
            1 AS Counter
    FROM    admanAdvertiserHierarchy_tbl ACC
    JOIN    dbo.admanAdvertiserObjectType_tbl AOT ON AOT.AdvertiserObjectTypeId = ACC.AdvertiserObjectTypeId
              WHERE  (EXISTS
                         (SELECT 1
                          FROM    dbo.admanAdvertiserHierarchy_tbl CAMP
                          JOIN    dbo.admanAdvertiserAdGroup_tbl AG ON CAMP.AdvertiserHierarchyId = AG.AdvertiserHierarchyId
                          JOIN    dbo.admanAdvertiserCreative_tbl AC ON AC.AdvertiserAdGroupId = AG.AdvertiserAdGroupId
                          AND     CAMP.ParentAdvertiserHierarchyId = ACC.AdvertiserHierarchyId
                          WHERE   CAMP.ERROR = 0
                                  AND AC.Dirty & 7 > 0
                                  AND AC.ERROR = 0
                                  AND AG.ERROR = 0 ))

它阻止优化器有效地使用索引。试图达到以下结果

    Title                               AdvertiserHierarchyId       Counter
    trcom65@travelrepublic.co.uk        15908                       1
    paul570@travelrepublic.co.uk        37887                       1
    es88@travelrepublic.co.uk           37383                       1
    it004@travelrepublic.co.uk          27006                       1
    011                                 10526                       1
    013                                 10528                       1
    033                                 12013                       1
    062                                 17380                       1
    076                                 20505                       1

这是脏 tinyint 列的计数

    Dirty   total
    0       36340607
    1       117569
    2       873553
    3       59

链接到静态原因表

    DirtyReasonId   Title
    0               Nothing
    1               Overnight Engine
    2               End To End
    3               Overnight And End To End
    4               Pause Resume
    5               Overnight Engine and Paused
    6               Overnight Engine E2E and Paused
    7               All Three
4

1 回答 1

3

如果您特别询问 BITWISE AND 运算符的使用,我相信您是正确的,并且 SQL Server 不太可能将其视为 sargable,至少,与 Dirty 作为前导列的索引不同。

您只显示正在使用的最低两位(Dirty 的最大值为 3),但您正在测试最低三位。

因此,AC.Dirty > 0假设 3 是 Dirty 的最大值,将返回等效结果。但是有可能设置了其他(高阶)位,例如 Dirty 可以设置为 8。因此,如果目的是只检查最低三位,那么我们需要确保只测试这三个最低位。这个表达式可以做到这一点,其中一个谓词是 sargable:

( AC.Dirty > 0 AND AC.Dirty % 8 > 0 )

这基本上首先测试是否设置了任何位AC.Dirty,然后检查是否设置了最后三位中的任何一个。(我们使用 MODULO 除法运算符返回 AC.Dirty 除以 8 的余数,这当然会返回 0 到 7 之间的整数值。如果我们得到一个零,那么我们知道低三位都没有已设置,否则我们知道至少有一个位已设置。

需要明确一点:谓词 onAC.Dirty > 0是多余的。如果您想确保数据库至少可以考虑使用现有索引Dirty作为前导列,则将其包含在此处。


我会提到另一个要考虑的选项是在表达式上添加一个持久的 COMPUTED COLUMN,并在其上创建一个索引。但这对于您在这里需要的东西来说似乎有点矫枉过正。


如果您特别询问有关在表admanAdvertiserCreative_tbl(AC) 上使用索引的问题,那么您最好的候选人可能会覆盖(AdvertiserAdGroupId, Error, Dirty).


下面的 SQL 重写应该返回等效的结果,可能具有更好的性能(取决于您的数据分布、索引等)

基本上,将 EXISTS(相关子查询)替换为子查询的 JOIN。子查询返回 CAMP.ParentAdvertiserHierarchyId 的不同值,这是您为关联子查询而引用的列。

这可能会或可能不会使用任何索引,具体取决于可用的索引。(它可能在主键上有聚集唯一索引,在外键上有非聚集索引,这应该有助于连接性能。)

未经测试:

SELECT  ACC.Title,
        ACC.AdvertiserHierarchyId,
        1 AS Counter
FROM    admanAdvertiserHierarchy_tbl ACC
JOIN    dbo.admanAdvertiserObjectType_tbl AOT 
        ON AOT.AdvertiserObjectTypeId = ACC.AdvertiserObjectTypeId
JOIN   (SELECT    CAMP.ParentAdvertiserHierarchyId
          FROM    dbo.admanAdvertiserHierarchy_tbl CAMP
          JOIN    dbo.admanAdvertiserAdGroup_tbl AG 
            ON    CAMP.AdvertiserHierarchyId = AG.AdvertiserHierarchyId
          JOIN    dbo.admanAdvertiserCreative_tbl AC 
            ON    AC.AdvertiserAdGroupId = AG.AdvertiserAdGroupId
         WHERE    CAMP.ERROR = 0
           AND    ( AC.Dirty > 0 AND AC.Dirty % 8 > 0 )
           AND    AC.ERROR = 0
           AND    AG.ERROR = 0 )
         GROUP BY CAMP.ParentAdvertiserHierarchyId
       ) c
  ON c.ParentAdvertiserHierarchyId = ACC.AdvertiserHierarchyId
于 2012-06-27T15:57:07.237 回答