临时加速查询表

时间:2018-04-30 16:00:08

标签: mysql date count

我需要在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

...

1 个答案:

答案 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'只是在一个月的第一天。看起来填充临时表会获得唯一的日期值,因此我们不会得到重复的内容。