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