【发布时间】:2017-03-05 17:17:59
【问题描述】:
基于联接表比嵌套查询更有效的假设,我一直在尝试优化一些 SQL 查询。我多次加入同一个表以对数据执行不同的分析。
我有 2 张桌子:
交易:
id | date_add | merchant_ id | transaction_type | amount
1 1488733332 108 add 20.00
2 1488733550 108 remove 5.00
还有一个只列出日期的日历表,以便我可以在特定日期没有交易的情况下创建空记录:
日历:
id | datefield
1 2017-03-01
2 2017-03-02
3 2017-03-03
4 2017-03-04
我在交易表中有数千行,我正在尝试获取每月总交易和不同类型交易的年度摘要(即总共 12 行),其中
- 交易 = 所有“金额”的总和,
- additions = 所有“金额”的总和,其中 transaction_type = “add”
- 赎回 = 所有“金额”的总和,其中 transaction_type = “删除”
结果:
month | transactions | additions | redemptions
Jan 15 12 3
Feb 20 15 5
...
我的初始查询如下所示:
SELECT COALESCE(tr.transactions, 0) AS transactions,
COALESCE(ad.additions, 0) AS additions,
COALESCE(re.redemptions, 0) AS redemptions,
calendar.date
FROM (SELECT DATE_FORMAT(datefield, '%b %Y') AS date FROM calendar WHERE datefield LIKE '2017-%' GROUP BY YEAR(datefield), MONTH(datefield)) AS calendar
LEFT JOIN (SELECT COUNT(transaction_type) as transactions, from_unixtime(date_add, '%b %Y') as date_t FROM transactions WHERE merchant_id = 108 GROUP BY from_unixtime(date_add, '%b %Y')) AS tr
ON calendar.date = tr.date_t
LEFT JOIN (SELECT COUNT(transaction_type = 'add') as additions, from_unixtime(date_add, '%b %Y') as date_a FROM transactions WHERE merchant_id = 108 AND transaction_type = 'add' GROUP BY from_unixtime(date_add, '%b %Y')) AS ad
ON calendar.date = ad.date_a
LEFT JOIN (SELECT COUNT(transaction_type = 'remove') as redemptions, from_unixtime(date_add, '%b %Y') as date_r FROM transactions WHERE merchant_id = 108 AND transaction_type = 'remove' GROUP BY from_unixtime(date_add, '%b %Y')) AS re
ON calendar.date = re.date_r
我尝试对其进行优化和清理,删除嵌套语句并提出以下建议:
SELECT
DATE_FORMAT(cal.datefield, '%b %d') as date,
IFNULL(count(ct.amount),0) as transactions,
IFNULL(count(a.amount),0) as additions,
IFNULL(count(r.amount),0) as redeptions
FROM calendar as cal
LEFT JOIN transactions as ct ON cal.datefield = date(from_unixtime(ct.date_add)) && ct.merchant_id = 108
LEFT JOIN transactions as r ON r.id = ct.id && r.transaction_type = 'remove'
LEFT JOIN transactions as a ON a.id = ct.id && a.transaction_type = 'add'
WHERE cal.datefield like '2017-%'
GROUP BY month(cal.datefield)
我惊讶地发现修改后的语句比我的数据集的原始语句慢了大约 20 倍。我错过了某种逻辑吗?考虑到我要多次加入同一个表,是否有更好的方法通过更简化的查询来实现相同的结果?
编辑: 因此,为了进一步解释我正在寻找的结果 - 我希望一年中的每个月都有一行(12 行),每个月有一列用于显示每个月的总交易、总添加和总赎回。
第一个查询我在大约 0.5 秒内得到结果,但第二个查询我在 9.5 秒内得到结果。
【问题讨论】:
-
您可以添加解释并发布优化和非优化查询的结果吗?
-
我真的不会为此烦恼日历表
-
我看到你在第二个查询中使用了
&&,在 LEFT JOIN 的 ON 语句中?他们应该是AND -
您能解释一下结果集中的列吗?我相信这个任务可以用一种不太复杂的方式来解决。
-
@PaulSpiegel 我在那里添加了一些编辑来解释预期结果
标签: mysql join optimization