使用带有内部存在检查的IF EXISTS的可疑性能

时间:2011-04-21 13:12:25

标签: sql-server-2008-r2

这是一个存储过程..这个if语句,然后我做了一点工作。 @AsOfDate是 date 数据类型的传入变量。我的问题是为什么我通过删除最内层存在来获得更好的性能,但只有当整个语句处于IF EXISTS 时才会获得更好的效果?

两个表:

  • dbo.TXXX_InventoryDe​​tail - 13亿条记录......最新动态
  • dbo.TXXX_InventoryFull - 980万条记录..最新动态

说明:

if exists (select 1
             from dbo.TXXX_InventoryDetail o
            where exists (select 1
                           from dbo.TXXX_InventoryFull i
                          where i.C001_AsOfDate= o.C001_AsOfDate
                            and i.C001_ProductID=o.C001_ProductID
                            and i.C001_StoreNumber=o.C001_StoreNumber
                            and i.C001_AsOfDate=@AsOfDate
                            and (i.C001_LastModelDate!=o.C001_LastModelDate
                                  or o.C001_InventoryQty!=o.C001_InventoryQty
                                  or i.C001_OnOrderQty!=o.C001_OnOrderQty
                                  or i.C001_TBOQty!=o.C001_TBOQty
                                  or i.C001_ModelQty!=o.C001_ModelQty
                                  or i.C001_TBOAdjustQty!=o.C001_TBOAdjustQty
                                  or i.C001_ReturnQtyPending!=o.C001_ReturnQtyPending
                                  or i.C001_ReturnQtyInProcess!=o.C001_ReturnQtyInProcess
                                  or i.C001_ReturnQtyDueOut!=o.C001_ReturnQtyDueOut))
              and o.C001_AsOfDate=@AsOfDate)

输出:

  • 表'TXXX_InventoryFull'。扫描计数9240262,逻辑读取29548864
  • 表'T001_InventoryDe​​tail'。扫描计数1,逻辑读取17259

如果我删除第二个存在并进行加入:

 if exists (select 1
             from dbo.TXXX_InventoryDetail o,
                  dbo.TXXX_InventoryFull i
            where i.C001_AsOfDate= o.C001_AsOfDate
                            and i.C001_ProductID=o.C001_ProductID
                            and i.C001_StoreNumber=o.C001_StoreNumber
                            and i.C001_AsOfDate=@AsOfDate
                            and (i.C001_LastModelDate!=o.C001_LastModelDate
                                  or o.C001_InventoryQty!=o.C001_InventoryQty
                                  or i.C001_OnOrderQty!=o.C001_OnOrderQty
                                  or i.C001_TBOQty!=o.C001_TBOQty
                                  or i.C001_ModelQty!=o.C001_ModelQty
                                  or i.C001_TBOAdjustQty!=o.C001_TBOAdjustQty
                                  or i.C001_ReturnQtyPending!=o.C001_ReturnQtyPending
                                  or i.C001_ReturnQtyInProcess!=o.C001_ReturnQtyInProcess
                                  or i.C001_ReturnQtyDueOut!=o.C001_ReturnQtyDueOut)
              and o.C001_AsOfDate=@AsOfDate)

输出:

  • 表'TXXX_InventoryDe​​tail'。扫描计数0,逻辑读取333952
  • 表'TXXX_InventoryFull'。扫描计数1,逻辑读取630

现在..我认为如果存在的原因是,如果我删除它并执行选择计数(*),就像这样:

select COUNT(*)
             from dbo.T001_InventoryDetail o
            where exists (select 1
                           from dbo.TXXX_InventoryFull i
                          where i.C001_AsOfDate= o.C001_AsOfDate
                            and i.C001_ProductID=o.C001_ProductID
                            and i.C001_StoreNumber=o.C001_StoreNumber
                            and i.C001_AsOfDate=@AsOfDate
                            and (i.C001_LastModelDate!=o.C001_LastModelDate
                                  or o.C001_InventoryQty!=o.C001_InventoryQty
                                  or i.C001_OnOrderQty!=o.C001_OnOrderQty
                                  or i.C001_TBOQty!=o.C001_TBOQty
                                  or i.C001_ModelQty!=o.C001_ModelQty
                                  or i.C001_TBOAdjustQty!=o.C001_TBOAdjustQty
                                  or i.C001_ReturnQtyPending!=o.C001_ReturnQtyPending
                                  or i.C001_ReturnQtyInProcess!=o.C001_ReturnQtyInProcess
                                  or i.C001_ReturnQtyDueOut!=o.C001_ReturnQtyDueOut))
              and o.C001_AsOfDate=@AsOfDate
  • TXXX_InventoryFull”。扫描计数41,逻辑读取692
  • T001_InventoryDe​​tail”。扫描计数65,逻辑读取17477
  • 工作台”。扫描计数0,逻辑读取0

3 个答案:

答案 0 :(得分:2)

通常认为应该避免在谓词中执行协调的子查询,因为这些子查询会强制嵌套循环连接。在查询大型数据集时,尤其是在尝试发现集合之间存在差异的情况下,允许查询优化器在散列,合并和嵌套循环算法之间动态选择是很重要的,如果使用协调子查询构造查询,这可能是不可能的。 。最好在FROM子句中将它们创建为派生表。

答案 1 :(得分:1)

我在SQL 08 R2服务器上使用EXISTS语句发现了类似的问题,其中完全相同的语句在SQL 08和SQL 05上运行良好。

我发现改变了像

这样的东西
WHILE EXISTS(SELECT * FROM X)

会超级慢,但是:

WHILE ISNULL((SELECT TOP 1 ID FROM X), 0) <> 0

再次跑得很快。

对我而言,这似乎是一个R2问题......

答案 2 :(得分:0)

我猜你使用联接时得到的计划大不相同。也许行数(非常大的外部表,较小的内部表)的不平衡使得优化器适合,但是它可以通过连接更容易地消除行(您可能会看到具有更差查询的其他循环操作符)。在没有看到计划或能够重现的情况下难以真正猜测,但是你应该始终尽可能地在计划的早期消除大多数行。通过几个运算符/子查询回退数百万行只是为了在计划的后期消除大部分行,几乎肯定会产生更差的性能。