我需要在mysql中加速查询需要45秒,我需要计算几个月/年,包括表中没有结果的月份,因为我创建了一个临时的日期表然后我启动以下查询,我该如何加快速度?
//CREATE TABLE OF DATES AND INSERT
CREATE TEMPORARY TABLE fechas(fecha date);
INSERT INTO fechas(fecha)
select * from
(select adddate("1970-01-01",t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) selected_date from
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
where selected_date between "2017-01-01" and "2018-01-01"
order by selected_date;
// QUERY
SELECT DATE_FORMAT(f.fecha, "%m-%Y") as data,
ifnull((
SELECT ifnull(COUNT(*),0)
FROM cupons c
WHERE YEAR(c.dataCupo) = YEAR(f.fecha)
AND MONTH(c.dataCupo) = MONTH(f.fecha)
and c.empresa=1
AND c.proveidor!="VINCULADO"
group by YEAR(c.dataCupo), MONTH(c.dataCupo)
ORDER BY c.dataCupo
),0) AS num
FROM fechas f
where f.fecha BETWEEN "2017-01-01" and "2018-01-01"
GROUP BY YEAR(f.fecha),MONTH(f.fecha);
//结果:
数据| NUM
01-2018 | 15
02-2018 | 0
03-2018 | 20
04-2018 | 0
...
答案 0 :(得分:1)
在函数中包装列将阻止MySQL有效使用索引。
WHERE YEAR(c.dataCupo) = ...
AND MONTH(c.dataCupo) = ...
这是一种允许MySQL在适当的索引上使用范围扫描操作的模式
WHERE c.dataCupo >= ...
AND c.dataCupo < ...
SELECT列表中的相关子查询将多次执行。如果我们要走那条路,那么最好先将fechas
分组为FIRST,然后每个月执行子查询,减少执行次数。
但我不会这样做,我会使用外连接操作。
我只能从fechas
每月获得一行,并按月获得相应的计数,而不是按天获得。
如果没有对临时表进行更改,那么就像这样:
SELECT DATE_FORMAT(f.fecha, "%m-%Y") AS data
, COUNT(c.dataCupo) AS num
FROM fechas f
LEFT
JOIN cupons c
ON c.dataCupo >= f.fecha
AND c.dataCuop < f.fecha + INTERVAL 1 MONTH
AND c.empresa = 1
AND c.proveidor != 'VINCULADO'
WHERE f.fecha >= '2017-01-01'
AND f.fecha < '2018-01-01'
AND DATE_FORMAT(f.fecha,'%d') = '01'
GROUP
BY f.fecha
请注意,条件DATE_FORMAT(f.fecha,'%d') = '01'
只是在一个月的第一天。看起来填充临时表会获得唯一的日期值,因此我们不会得到重复的内容。