Sql server 2008 r2 使用IF EXISTS和内部存在性检查的性能有问题
这是在一个存储过程中..这个if语句,然后我做一些工作。@AsOfDate是日期数据类型的传入变量。我的问题是,为什么只有当整个语句都在IF-exists中时,才能通过删除最内部的exists来获得更好的性能 这两个表格: dbo.TXXX_InventoryDetail-13亿条记录..最新统计数据 dbo.TXXX_InventoryFull-980万条记录..最新统计数据 声明:Sql server 2008 r2 使用IF EXISTS和内部存在性检查的性能有问题,sql-server-2008-r2,Sql Server 2008 R2,这是在一个存储过程中..这个if语句,然后我做一些工作。@AsOfDate是日期数据类型的传入变量。我的问题是,为什么只有当整个语句都在IF-exists中时,才能通过删除最内部的exists来获得更好的性能 这两个表格: dbo.TXXX_InventoryDetail-13亿条记录..最新统计数据 dbo.TXXX_InventoryFull-980万条记录..最新统计数据 声明: if exists (select 1 from dbo.TXXX_Inventor
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)
io输出:
表“TXXX_InventoryFull”。扫描计数9240262,逻辑读取29548864
表“T001\U库存详情”。扫描计数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)
io输出:
表“TXX\U库存详情”。扫描计数0,逻辑读取333952
表“TXXX_InventoryFull”。扫描计数1,逻辑读取630
现在..我认为它是if存在的原因是如果我删除它并进行如下选择计数*:
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_库存已满'。扫描计数41,逻辑读取692
T001_库存详情”。扫描计数65,逻辑读取17477
“工作台”。扫描计数0,逻辑读取0
我猜当你使用join时,你得到的计划是完全不同的。也许行数的不平衡——外部表非常大,内部表较小——使优化器适合,但它可能更容易使用联接消除行——您可能会看到其他循环运算符使用更糟糕的查询。在看不到计划或无法复制的情况下,很难进行真正的猜测,但您应该始终以尽可能早地在计划中消除大多数行为目标。在计划的后期,通过几个运算符/子查询收回数百万行,而仅仅删除其中的大多数行,几乎肯定会产生更差的性能。我在SQL 08 R2服务器上使用EXISTS语句时发现了类似的问题,在SQL 08和SQL 05上,完全相同的语句可以正常运行 我发现这种改变
WHILE EXISTS(SELECT * FROM X)
会非常慢,但是:
WHILE ISNULL((SELECT TOP 1 ID FROM X), 0) <> 0
又跑得非常快了
对我来说,这似乎是一个R2问题……一般来说,应该避免在谓词中执行协调子查询,因为这些子查询往往会强制进行嵌套循环联接。在查询大型数据集时,尤其是在试图发现数据集之间的差异时,允许查询优化器在散列、合并和嵌套循环算法之间动态选择是很重要的,如果使用协调子查询构造查询,这可能是不可能的。最好在FROM子句中将这些表创建为派生表