尝试优化以下查询,因为它运行速度非常慢。我对它做了一些优化但是窗台运行非常慢> 30秒。
这是查询:
set @_YEAR = 2014;
set @_MONTH = 1;
set @_PRODUCTS = '53';
set @_START = date(@_YEAR * 10000 + 1 * 100 + 1);
set @_END = date_add(date(@_YEAR * 10000 + 1 * 100 + 1), interval 1 year);
explain SELECT TG, TS, `MONTH`
FROM (
SELECT SG.company, SUM(SG.Gain) as TG, SUM(SG.Spill) as TS, SG.`MONTH`
FROM (
(SELECT c.called as customer, c.calling as company, MONTH(c.`end`) as 'MONTH',
@G := if(@prevComp <> c.calling AND @prevCust = c.called AND @prevDate = DATE_FORMAT(c.`end`,'%Y-%m-%d'), 1, 0) as Gain,
@S := 0 as Spill,
@prevCust := c.called as prevCust,
@prevComp := c.calling as prevComp,
@prevDate := DATE_FORMAT(c.`end`,'%Y-%m-%d') as prevDate
FROM cdrdata_archive c CROSS JOIN
(SELECT @prevComp := 0, @prevCust := 0, @prevDate := 0) prevVals
where c.`end` >= @_START and c.`end` < @_END
AND c.called != 'Anonymous'
AND CAST(c.`duration` AS UNSIGNED) > 30
ORDER BY c.called, c.`end` limit 5000000)
UNION ALL
(SELECT c.called as customer, c.calling as company, MONTH(c.`end`) as 'MONTH',
@G := 0 as Gain,
@S := if(@nextComp <> c.calling AND @nextCust = c.called AND @nextDate = DATE_FORMAT(c.`end`,'%Y-%m-%d'), 1, 0) as Spill,
@nextCust := c.called as nextCust,
@nextComp := c.calling as nextComp,
@nextDate := DATE_FORMAT(c.`end`,'%Y-%m-%d') as nextDate
FROM cdrdata_archive c CROSS JOIN
(SELECT @nextComp := 0, @nextCust := 0, @nextDate := 0) nextVals
where c.`end` >= @_START and c.`end` < @_END
AND c.called != 'Anonymous'
AND CAST(c.`duration` AS UNSIGNED) > 30
ORDER BY c.called, c.`end` desc limit 5000000)
) SG
GROUP BY SG.company, SG.`MONTH`
) SGgrouped
JOIN products p ON p.Number = SGgrouped.company
Where p.id IN (@_PRODUCTS)
ORDER BY SGgrouped.`MONTH`
这是输入:
CREATE TABLE `cdrdata_archive` (
`CustomerID` varchar(10) DEFAULT NULL,
`callid` varchar(20) NOT NULL,
`called` varchar(14) DEFAULT NULL,
`description` varchar(20) DEFAULT NULL,
`calling` varchar(16) DEFAULT NULL,
`dtn` varchar(14) DEFAULT NULL,
`start` datetime DEFAULT NULL,
`end` datetime DEFAULT NULL,
`answered` datetime DEFAULT NULL,
`duration` varchar(5) DEFAULT NULL,
`talktime` varchar(5) DEFAULT NULL,
`tta` int(3) DEFAULT NULL,
PRIMARY KEY (`callid`),
UNIQUE KEY `callid_UNIQUE` (`callid`),
KEY `called` (`called`,`start`,`end`),
KEY `abandoned_from` (`calling`,`talktime`,`end`),
KEY `called end` (`calling`,`end`),
KEY `start` (`start`),
KEY `calling` (`calling`),
KEY `endcalling` (`end`,`calling`),
KEY `productdur` (`calling`,`end`,`duration`),
KEY `endcallingdur` (`end`,`calling`,`duration`),
KEY `company` (`CustomerID`,`end`),
KEY `calling end` (`end`,`called`,`calling`),
KEY `end` (`end`) USING BTREE,
KEY `call_id_desc` (`callid`) USING BTREE
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
这是EXPLAIN声明:
以下是SHOW VARIABLES LIKE '%buffer%';
问:如何优化此查询?
答案 0 :(得分:2)
主要问题是(参见上面的评论)是你的表格,就像这种类型的CASTING
AND CAST(c.`duration` AS UNSIGNED) > 30
MySQL不能使用任何KEY,必须扫描整个表。
修改
请出示详细说明
EXPLAIN
SELECT c.called as customer, c.calling as company, MONTH(c.`end`) as 'MONTH',
@G := 0 as Gain,
@S := if(@nextComp <> c.calling AND @nextCust = c.called AND @nextDate = DATE_FORMAT(c.`end`,'%Y-%m-%d'), 1, 0) as Spill,
@nextCust := c.called as nextCust,
@nextComp := c.calling as nextComp,
@nextDate := DATE_FORMAT(c.`end`,'%Y-%m-%d') as nextDate
FROM cdrdata_archive c CROSS JOIN
(SELECT @nextComp := 0, @nextCust := 0, @nextDate := 0) nextVals
where c.`end` >= @_START and c.`end` < @_END
AND c.called != 'Anonymous'
AND CAST(c.`duration` AS UNSIGNED) > 30
ORDER BY c.called, c.`end` desc
limit 5000000
答案 1 :(得分:1)
我在另一个论坛上给了你更长的答案。在这个论坛中,我看到一个只有8MB的微不足道的key_buffer_size。建议您将其设置为可用 RAM的约20%。