Ускорить таблицу запросов временно

0

Мне нужно ускорить запрос в 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
    Примечание: select adddate("1970-01-01" .... selected_date between "2017-01-01" если вы не измените 1970-01-01 на 2017-01-01 потому что 2017-01-01 ваш дата начала, а не 1970-01-01
  • 0
    Почему бы вам просто не создать статическую календарную таблицу с правильными индексами?
Показать ещё 1 комментарий
Теги:
date
count

1 ответ

1
Лучший ответ

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

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

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

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

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

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

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

  • 0
    year (c.dataCupo) = year (f.fecha) и .... его для объединения таблицы информации (cupons) и таблицы дат (fechas)
  • 0
    @RaymondNijland: под «эффективным использованием» я подразумевал операцию сканирования диапазона, а не полное сканирование. MySQL может выполнить полное сканирование индекса ... моя точка зрения заключается в том, что перенос этого столбца в функцию заставляет MySQL оценивать эту функцию для каждой строки в таблице. А с помощью OP-запроса MySQL выполняет полное сканирование таблицы cupons для каждого из 365 дней, возвращаемых из феч. Гораздо эффективнее использовать сканирование диапазона для каждого отдельного дня ... при условии равномерного распределения значений дат, сканирование диапазона для одного n каждого выполнения быстро устраняет 99,7% строк из рассмотрения.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню