我有Table Customer_AJ(客户varchar,项目编号,购买日期时间),并且我有两个表,其中包含成功和失败,并且我希望所有在未来30分钟内没有成功的失败的客户。
我尝试使用不存在但是它在hashMatch上循环(正如我在查询计划中看到的那样,Iam附加查询和执行计划的屏幕截图..
with Failure as (
select * from [dbo].[Customer_AJ] where item in ( 20, 34, 35, 36, 37, 47, 53, 54 )
) ,
success as (
select * from Customer_AJ where Item in ( 1, 3, 40, 42, 43, 5 )
) ,
final as (
select f.customer, f.item,f.purchase from Failure f left outer join success s
on f.customer = s.customer and DATEDIFF( minute , f.purchase , s.purchase ) between 0 and 30
where s.customer is NULL
)
select * from final
答案 0 :(得分:1)
核心问题将是列上的DATEDIFF函数。它将导致扫描。如果你有数百万行,那么每次都会很慢。您需要找到一种在不应用该功能的情况下加入数据的方法。
完整的执行计划可能是其他建议,而不是图像。
答案 1 :(得分:0)
就个人而言,在寻找不存在的东西时,我更喜欢使用“显而易见的”。 WHERE NOT EXISTS()
语法。查询优化器将使用与LEFT OUTER JOIN ... WHERE field IS NULL
语法相同的计划,但它更容易阅读。
SELECT f.customer, f.item, f.purchase
FROM Failure f
WHERE NOT EXISTS ( SELECT *
FROM Success s
WHERE s.customer = f.customer
AND DATEDIFF( minute , f.purchase , s.purchase ) between 0 and 30 )
DateDiff()
是一个性能杀手,因为没有办法快速获得匹配数据,优化器也无法预测匹配的行数。要解决此问题,您可以尝试将DateDiff()
转换为DateAdd()
构造:
SELECT f.customer, f.item, f.purchase
FROM Failure f
WHERE NOT EXISTS ( SELECT *
FROM Success s
WHERE s.customer = f.customer
AND s.purchase >= f.purchase
AND s.purchase <= DateAdd(minute, +30, f.purchase) )
假设您的Customer_AJ
表上有一个索引,其中包含以下字段:customer, item, purchase
这应该会使Failure
和Success
之间的联接相当快。
(您可能希望尝试并交换字段的顺序,因为它确实依赖于您的数据的样子,但由于我们在purchase
列中有一系列匹配项。我很确定你想保留最后一个。)