【问题标题】:Azure SQL Database Left Join looping with 1.5 million records包含 150 万条记录的 Azure SQL 数据库左连接循环
【发布时间】:2017-08-30 11:50:49
【问题描述】:

我有表 Customer_AJ(客户 varchar,项目编号,购买日期时间),我有两个表,其中有 Sucess 和 Failure,我想要该客户在接下来的 30 分钟内没有成功的所有失败。

我使用 Not exist 进行了尝试,但它在 hashMatch 处循环(正如我在 queryplan 中看到的那样,我正在附加查询和执行计划的屏幕截图 ..

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

Here is the Query Execution plan for it

【问题讨论】:

  • 不是实时查询统计信息的屏幕截图,而是通过实际执行计划 XML 到 brentozar.com/pastetheplan 并将链接添加到您的问题。

标签: sql-server azure indexing query-optimization azure-sql-database


【解决方案1】:

核心问题将是列上的 DATEDIFF 函数。这将导致扫描。如果您有数百万行,那么每次都会很慢。您需要找到一种在不应用该功能的情况下加入数据的方法。

如果有完整的执行计划,而不是图像,则可能会提供其他建议。

【讨论】:

  • 有什么方法可以删除 datediff 函数。尤其是这个条件连接?
  • 我不知道推动这一点的业务规则,但是将日期和时间值计算为变量,然后与每一列的该变量进行比较是一种方法。如果规则是找到一个相距 30 分钟的值,那么找出如何在不计算查询的 WHERE、ON 或 HAVING 子句的情况下捕获该值。
【解决方案2】:

就个人而言,在寻找不存在的东西时,我更喜欢使用“明显的”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 这应该使FailureSuccess 之间的连接相当快。

(您可能想要尝试并交换字段的顺序,因为它确实有点取决于您的数据是什么样的,但由于我们有一系列匹配 purchase 列我很确定你想把那个留到最后)。

【讨论】:

    猜你喜欢
    • 2019-09-16
    • 2010-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-29
    • 1970-01-01
    相关资源
    最近更新 更多