如何重写 SQL 查询以提高效率?

How to re-write SQL query to be more efficient?

我有一个查询,它本身大小合适,但其中有一部分将它变成了大得离谱的东西(数十亿行返回类型的东西)。

肯定有比我写的更好的写法

为了简化相关查询部分,它从一个 table 中获取客户详细信息,并尝试在他们的储蓄和支出账户中找到最近的交易日期(不是实际情况,但接近够了)。

我用左连接加入它,因为如果某人(例如)没有储蓄账户,我仍然希望弹出客户详细信息。但是当有几十万客户,几万笔交易的时候,就有点慢了运行。

select client_id, max(e.transation_date), max(s.transaction_date)
from client_table c
    left join everyday_account e
        on c.client_id = e.client_id
    left join savings_account s
        on c.client_id = s.client_id
group by client_id

我对此还是个新手,所以我不太了解如何优化事物,所以有什么我应该关注的吗?也许不同的连接,或者 max() 以外的东西?

我在尝试简化它时可能遗漏了一些关键细节,如果是这样请告诉我!

没有 WHEREHAVING 子句,这基本上意味着您的 SQL 查询中没有显式过滤。但是,我们仍然可以尝试使用适当的索引来优化连接。考虑:

CREATE INDEX idx1 ON everyday_account (client_id, transation_date);

CREATE INDEX idx2 ON savings_account (client_id, transation_date);

如果选择使用这两个索引,应该会加速查询中的两个左连接。我还介绍了这两种情况下的 transaction_date,以防有帮助。

旁注:您可能还想考虑只拥有一个包含所有客户帐户的 table。包括一个单独的列来区分日常账户和储蓄账户。

有时先聚合,然后加入聚合结果更快。但这取决于实际使用的 DBMS 和其他几个因素。

select client_id, e.max_everyday_transaction_date, s.max_savings_transaction_date
from client_table c
  left join (
    select client_id, max(transaction_date) as max_everyday_transaction_date
    from everyday_account 
    group by client_id
  ) e on c.client_id = e.client_id
  left join (
    select client_id, max(transaction_date) as max_savings_transaction_date
    from savings_account
  ) s on c.client_id = s.client_id

Tim Biegeleisen 建议的索引在这种情况下也应该有所帮助。

但由于查询必须处理所有表中的所有行,因此除了投入更多硬件外,没有什么好的方法可以加快此查询的速度。如果您的数据库支持它,请确保启用了并行查询(这将把总工作分配给后端的多个线程,如果 I/O 系统可以跟上,这可以大大提高查询性能)

我会建议相关子查询:

select client_id,
       (select max(e.transation_date)
        from everyday_account e
        where c.client_id = e.client_id
       ),
       (select max(s.transaction_date)
        from savings_account s
        where c.client_id = s.client_id
       )
from client_table c;

以及 everyday_account(client_id, transaction_date desc)savings_account(client_id, transaction_date desc) 上的索引。

子查询基本上应该是索引查找(或非常有限的索引扫描),不需要额外的连接。