【问题标题】:Self-Joins: is there a way to improve the performance of this query?自联接:有没有办法提高这个查询的性能?
【发布时间】:2022-11-01 20:33:06
【问题描述】:

所有这一切的目的是创建一个查找表以避免自连接,这将涉及将相同数据与更大的数据集连接。

在这种情况下,销售订单可能具有开单给客户 ID 和发运给客户 ID 中的一个或两个。

这里的表格是来自 5 个不同服务器的数据聚合,由 box_id 区分。客户表约为 170 万行,sales_order 约为 5500 万行。最终结果是大约 5200 万条记录,平均需要大约 80 分钟才能运行。

查询:

 SELECT DISTINCT sog.box_id  ,
    sog.sales_order_id  ,
    cb.cust_id AS bill_to_customer_id  ,
    cb.customer_name AS bill_to_customer_name  ,
    cs.cust_id AS ship_to_customer_id  ,
    cs.customer_name AS ship_to_customer_name 
FROM sales_order sog 
LEFT JOIN customer cb  ON cb.cust_id = sog.bill_to_id   AND cb.box_id = sog.box_id 
LEFT JOIN customer cs  ON cs.cust_id = sog.ship_to_id   AND cs.box_id = sog.box_id

执行计划:

https://www.brentozar.com/pastetheplan/?id=SkjhXspEs

所有这些都发生在 SQL Server 上。

我尝试将账单复制到 CTE 并将其运送到客户集并加入这些集,但没有发现任何性能优势。

这些表上的唯一索引是主键(合成 ID)。有点奇怪的是,执行计划分析器不建议向任一表添加任何索引。它通常希望我对几乎所有内容都进行索引。

我不知道一定有办法让它运行得更快,但我正在努力改进我的查询优化并且已经达到了我的知识极限。非常感谢任何见解。

【问题讨论】:

  • 您的查询正在对两个表执行表扫描并扫描Customer 两次。 (Cust_Id) include (Customer_Name) 上的覆盖索引可能是有益的,但理想情况下,您应该只点击一次表格,您可以使用 outer apply() 中的条件逻辑来完成。最好有实际的计划而不是估计的计划以确定最大的成本在哪里。你需要清楚的?
  • @@version 是什么?理想情况下,此查询可以受益于批处理模式
  • “平均需要大约 80 分钟才能运行” - 在哪里?如果您将大约 52M 记录返回给客户端,那么您可能会看到大量等待,因为这跟不上。 80 分钟只对中等大小的表和一些哈希连接进行三表扫描,否则肯定会出乎意料地慢......
  • 实际执行计划的 XML 是什么。没有估计。看起来像? (这将包含遇到的等待统计信息和每个操作员的时间以及任何溢出的详细信息)

标签: sql sql-server query-optimization materialized-views


【解决方案1】:

当您运行像您这样的查询时——没有 WHERE 过滤器的查询——通常 DBMS 决定它必须扫描整个表。 (在 SQL Server 执行计划中,“聚集索引扫描”意味着它正在扫描整个表。)它当然必须处理表中的所有数据。您要创建的查找表通常称为“物化视图”。 (online version of SQL server 内置了对物化视图的支持,但其他版本仍然不支持。)

根据您使用数据的方式,您最好避免使用此具体化查找表。如果您对建议的查找表的所有使用都涉及使用 WHERE 子句过滤掉一小部分行,那么普通的非物化视图可能是一个不错的选择。当您提供涉及普通视图的查询时,查询计划器会将这些视图折叠到查询中,并可能会推荐有用的索引。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    • 2020-12-01
    • 2021-09-06
    • 2022-11-07
    • 1970-01-01
    • 2012-12-12
    • 2021-12-06
    相关资源
    最近更新 更多