我有一个表 t_date_interval_30,它是 365 个日历年日期的笛卡尔积,时间字段以 30 分钟为间隔递增。我将其用作挂起调用数据的框架。
t_date_interval_30
DATE, DAYNAME, INTERVAL
'2013-01-01', 'Tuesday', '00:00:00'
'2013-01-01', 'Tuesday', '00:30:00'
'2013-01-01', 'Tuesday', '01:00:00'
'2013-01-01', 'Tuesday', '01:30:00'
'2013-01-01', 'Tuesday', '02:00:00'
'2013-01-01', 'Tuesday', '02:30:00'
ETC...
接下来我有一个 View v_call_details,它是通话数据的汇总 View 。调用数据在每个发起的调用 session 中汇总为一行——每个调用 session 的来源可以有多行;即,从一个目标到另一个目标的调用滚动无人应答,调用的每一段都会增加一个新的记录行。
v_call_details
CLIENT, CSQ, SESS_ID, DATE, CALL_START, CONT_DISP, MET_SLA
'Acme','ACME_CSQ','123-123456789-01','2013-01-01','2013-01-01 00:12:34','ABANDONED',TRUE
'Acme','ACME_CSQ','123-123456998-01','2013-01-01','2013-01-01 00:45:02','HANDLED',TRUE
'Acme','ACME_CSQ','123-123457291-01','2013-01-02','2013-01-02 13:31:58','HANDLED',FALSE
ETC...
所以,当我运行下面的查询时,它需要很长时间。
SELECT
cd.`client`,
cd.`csq`,
di.`date`,
di.`dayname`,
di.`interval`,
count(cd.`sess_id`) AS `calls`,
(count(cd.`sess_id`) - sum(IF(cd.`cont_disp` = 'ABANDONED'
AND cd.`met_sla` > 0,
1,
0))) AS `presented`
FROM
t_date_interval_30 di
LEFT JOIN
v_call_details cd ON (di.`date` = cd.`date`
AND di.`interval` = SEC_TO_TIME((TIME_TO_SEC(cd.`call_start`) DIV 1800) * 1800))
WHERE
di.`date` BETWEEN '2013-05-01' AND '2013-05-02'
GROUP BY cd.`csq`, di.`date`, di.`interval`
我从未真正使用过索引(尽管我尝试过向 DATE 值和 CALL_START 值添加一些索引)。当我运行 EXPLAIN EXTENDED 时,我得到以下结果。
id, select_type, table, type, possible_keys, key, key_len, ref, rows, filtered, Extra
1, PRIMARY, di, range, i_date, i_date, 3, , 96, 100.00, Using where; Using temporary; Using filesort
1, PRIMARY, <derived2>, ALL, , , , , 153419, 100.00, ,
2, DERIVED, t_cisco_csq_agent_details, ALL , , , , 161925, 100.00, Using temporary; Using filesort
2, DERIVED, t_lkp_clients, ALL , , , , 56, 100.00, ,
如有任何建议,我们将不胜感激。现在,如果我运行查询,返回 2 天数据的结果大约需要 70 秒。按照这个速度,做一份 90 天的报告需要一个半小时……我需要找到一种方法来降低它。
最佳答案
首先,不要假设 90 天的数据所需的工作量是 2 天的 45 倍。您的查询正在对调用详细信息表进行全面扫描,这可能占了大部分工作量。 MySQL 可以通过 equijoin 将日期条件从 di
传播到 cd
。我不确定在这种情况下是否如此(因为第二个条件)。
其次,您正在使用 View 。这可能导致无法真正提高性能。您可以尝试,但您应该尝试在没有 View 的情况下编写查询。
我的下一个问题是这需要多长时间才能运行:
select cd.csq, cd.`date`,
SEC_TO_TIME((TIME_TO_SEC(cd.`call_start`) DIV 1800) * 1800)) as interval,
count(*)
from v_call_details cd
WHERE cd.`date` BETWEEN '2013-05-01' AND '2013-05-02';
如果这需要合理的时间,则测试 90 天。如果可行,那么您可以先进行聚合,然后再连接回 di
表。这只是一个想法。我怀疑真正的性能问题出在 View 中。
关于mysql - 长时间运行的 MYSQL 查询、Frame Table 和 View with grouping,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18368468/