我有三张桌子:
mail_info
列CustomerID, MailID, Opened
mail_ids
列MailID, MailType, SendDate
mail_data
列CustomerID, Item, Sales, PurchaseDate
我想对每个Sales
的{{1}}求和,按每个CustomerID
分组,并显示每个客户/日期对的二进制PurchaseDate
数据。
派生的Opened
是将每个basetable
与其对应日期相关联,以便在MailID
中使用。
这是我的问题:
mail_data
所需的输出示例:
SELECT CustomerID, Opened, SendDate, SUM(mail_data.Sales) FROM
(SELECT
mail_info.CustomerID,
mail_info.Opened,
mail_ids.SendDate
FROM mail_info
INNER JOIN mail_ids ON mail_info.MailID = mail_ids.MailID
WHERE mail_ids.MailType = 'E'
) AS basetable
INNER JOIN mail_data ON mail_data.PurchaseDate = basetable.SendDate
GROUP BY CustomerID, SendDate
ORDER BY CustomerID, SendDate ASC;
我可以立即运行基表# CustomerID, Opened, SendDate, SUM
1, 1, 2017-01-03, 5.68
1, 0, 2017-01-04, 4.92
1, 0, 2017-01-05, 43.23
2, 1, 2017-01-03, 12.65
2, 1, 2017-01-04, 283.24
2, 0, 2017-01-05, 74.23
,但是当我将SELECT
函数和SUM
添加到派生表时,查询将运行直到服务器超时(许多小时)。
INNER JOIN mail_data
表约有6亿行,其他表相对较小。
我在mail_data
上添加了一个索引,而mail_data.PurchaseDate
表明该索引正在查询中使用。我还增加了缓冲区大小并将数据移动到SSD。
这可能是服务器或数据库优化的问题,还是我的查询写得不正确?
谢谢!
答案 0 :(得分:1)
在MySQL中,除非需要,否则最好不要使用子查询(派生表)。它们倾向于具体化 - 作为临时表保存在磁盘上 - 这可能会妨碍性能。
所以,试试这个:
SELECT minf.CustomerID, minf.Opened, mi.SendDate, SUM(md.Sales)
FROM mail_info minf INNER JOIN
mail_ids mi
ON minf.MailID = mi.MailID INNER JOIN
mail_data md
ON md.PurchaseDate = mi.SendDate and
md.CustomerID = mi.CustomerID
WHERE mi.MailType = 'E'
GROUP BY minf.CustomerID, mi.SendDate
ORDER BY minf.CustomerID, mi.SendDate ASC;
我在JOIN
上添加了额外的CustomerID
条件。这似乎是合理的。
你的桌子正在处理很多行。您可能认为basetable
查询正在快速返回 - 但它可能只返回结果集中的第一行。 GROUP BY
需要读取所有数据,然后进行更多处理,因此需要更长的时间。