MySQL:大内部联接的总结

时间:2017-10-12 01:03:55

标签: mysql sql

我有三张桌子:

mail_infoCustomerID, MailID, Opened

mail_idsMailID, MailType, SendDate

mail_dataCustomerID, 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。

这可能是服务器或数据库优化的问题,还是我的查询写得不正确?

谢谢!

1 个答案:

答案 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需要读取所有数据,然后进行更多处理,因此需要更长的时间。