如何重写 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() 以外的东西?
我在尝试简化它时可能遗漏了一些关键细节,如果是这样请告诉我!
没有 WHERE
或 HAVING
子句,这基本上意味着您的 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)
上的索引。
子查询基本上应该是索引查找(或非常有限的索引扫描),不需要额外的连接。
我有一个查询,它本身大小合适,但其中有一部分将它变成了大得离谱的东西(数十亿行返回类型的东西)。
肯定有比我写的更好的写法
为了简化相关查询部分,它从一个 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() 以外的东西?
我在尝试简化它时可能遗漏了一些关键细节,如果是这样请告诉我!
没有 WHERE
或 HAVING
子句,这基本上意味着您的 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)
上的索引。
子查询基本上应该是索引查找(或非常有限的索引扫描),不需要额外的连接。