Ускорить таблицу запросов временно - PullRequest
0 голосов
/ 30 апреля 2018

Мне нужно ускорить запрос в 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 голосов
/ 30 апреля 2018

Обтекание столбцов в функциях помешает MySQL эффективно использовать индекс.

WHERE YEAR(c.dataCupo) = ... 
  AND MONTH(c.dataCupo) = ... 

Вот шаблон, который позволяет MySQL использовать операцию сканирования диапазона для соответствующего индекса

WHERE c.dataCupo >=  ... 
  AND c.dataCupo <   ...

Коррелированный подзапрос в списке SELECT будет выполнен несколько раз. Если мы собираемся пойти по этому пути, то было бы намного лучше получить группировку fechas done ПЕРВЫМ, а затем выполнять подзапрос для каждого месяца, сокращая количество выполнений.

Но я бы этого не сделал, я бы использовал операцию внешнего соединения.

И я получал бы только одну строку в месяц из 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' получает нас только в первый день месяца. Похоже, что заполнение временной таблицы дает нам уникальные значения даты, поэтому мы не получим дубликатов.

...