重写T-SQL按位逻辑

时间:2012-06-27 13:36:36

标签: sql-server tsql bit-manipulation

如何重写此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

1 个答案:

答案 0 :(得分:3)

如果您特别询问BITWISE AND运算符的使用,我相信您是正确的,并且SQL Server不太可能认为这是可以理解的,至少不是使用Dirty作为前导列的索引。

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

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

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

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

要明确:AC.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