2017-10-12 54 views
1

我有三个表:MySQL的:一个大的内琛加入

mail_info与列CustomerID, MailID, Opened

mail_ids与列MailID, MailType, SendDate

mail_data与列CustomerID, Item, Sales, PurchaseDate

我要总结的Sales对于每个CustomerID,按PurchaseDate分组,并且还显示垃圾箱ary 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 

我可以运行basetable SELECT瞬间,但是当我加入SUM功能和INNER JOIN mail_data到派生表,该查询会一直运行到服务器超时(几个小时)。

mail_data表约6亿行,其他表相对较小。

我在mail_data.PurchaseDate上添加了一个索引,而EXPLAIN表明该索引正在查询中使用。我还增加了缓冲区大小并将数据移至SSD。

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

谢谢!

回答

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; 

我对CustomerID添加额外JOIN条件。这似乎是合理的。

你的表正在处理很多行。您可能认为basetable查询正在快速返回 - 但它可能只返回结果集中的第一行。 GROUP BY需要读取全部的数据,然后进行更多的处理,所以需要更长的时间。

+0

感谢您的回答!不幸的是,查询仍然在一夜之间完成,并且还没有停止。我能做更多来优化查询吗?我觉得它不应该在SSD上花费这么长时间,并且CPU使用率只有13%。 –

+0

@GraysonWyker。 。 。我添加了一个'JOIN'条件,缺少这个条件可能解释性能问题。 –

+0

这工作,并把它带到2小时,谢谢! –