2016-10-09 6 views
0

У меня есть 2 таблицы:Низкая производительность запросов влево присоединение вид

describe CONSUMO 

Field  Type  Null Key  Default  Extra 
idconsumo int(11)  NO  PRI  NULL  auto_increment 
idkey  int(11)  NO  MUL  NULL  
ip   varchar(50) NO    Unknown 
fechahora datetime NO    NULL  


describe CONTRATADO 

Field  Type  Null Key  Default  Extra 
idkey  int(11)  NO  PRI  NULL  auto_increment 
idusuario int(11)  NO  MUL  NULL  
idproducto int(11)  NO  MUL  NULL  
key   varchar(64) NO  MUL  NULL  
descripcion varchar(50) YES    "API KEY" 
peticiones int(11)  YES    NULL  
caducidad datetime YES    NULL  

и вид (который возвращает последние 30 дней от NOW()):

CREATE VIEW `last_30_days` AS 
    SELECT 
     DATE_FORMAT((NOW() - INTERVAL ((`units`.`i` + (`tens`.`i` * 10)) + (`hundreds`.`i` * 100)) DAY), 
       '%M %e') AS `fecha`, 
     DATE_FORMAT((NOW() - INTERVAL ((`units`.`i` + (`tens`.`i` * 10)) + (`hundreds`.`i` * 100)) DAY), 
       '%Y%m%d') AS `fecha_order` 
    FROM 
     ((`0_9_range` `units` 
     JOIN `0_9_range` `tens`) 
     JOIN `0_9_range` `hundreds`) 
    WHERE 
     ((NOW() - INTERVAL ((`units`.`i` + (`tens`.`i` * 10)) + (`hundreds`.`i` * 100)) DAY) BETWEEN (NOW() - INTERVAL 1 MONTH) AND NOW()) 

Всякий раз, когда я выполнить запрос, так как например:

SELECT sub1.fecha, COUNT(idconsumo) as consumo 
FROM `last_30_days` `sub1` 
LEFT JOIN `CONSUMO` ON sub1.fecha = DATE_FORMAT(fechahora, "%M %e") 
LEFT JOIN `CONTRATADO` ON CONSUMO.idkey = CONTRATADO.idkey 
WHERE idusuario IS NULL OR idusuario = 1 
GROUP BY `sub1`.`fecha` 
ORDER BY `sub1`.`fecha_order` 

занимает довольно продолжительное время (~ 20 секунд).

Вот объяснить запроса:

id  select_type  table         type possible_keys key  key_len ref      rows Extra 
1  PRIMARY   <derived3>        ALL  NULL   NULL NULL NULL     10  "Using temporary; Using filesort" 
1  PRIMARY   <derived13>        ALL  NULL   NULL NULL NULL     10  "Using join buffer" 
1  PRIMARY   <derived23>        ALL  NULL   NULL NULL NULL     10  "Using where; Using join buffer" 
1  PRIMARY   CONSUMO         ALL  NULL   NULL NULL NULL     908553 
1  PRIMARY   CONTRATADO        eq_ref PRIMARY   PRIMARY 4  c1geoapi.CONSUMO.idkey 1  "Using where" 
23  DERIVED   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
24  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
25  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
26  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
27  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
28  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
29  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
30  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
31  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
32  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
NULL "UNION RESULT" <union23,24,25,26,27,28,29,30,31,32> ALL  NULL   NULL NULL NULL     NULL  
13  DERIVED   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
14  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
15  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
16  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
17  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
18  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
19  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
20  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
21  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
22  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
NULL "UNION RESULT" <union13,14,15,16,17,18,19,20,21,22> ALL  NULL   NULL NULL NULL     NULL  
3  DERIVED   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
4  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
5  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
6  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
7  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
8  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
9  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
10  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
11  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
12  UNION   NULL         NULL NULL   NULL NULL NULL     NULL "No tables used" 
NULL "UNION RESULT" <union3,4,5,6,7,8,9,10,11,12>   ALL  NULL   NULL NULL NULL     NULL  

Что я могу сделать для того, чтобы улучшить мой запрос? Почему это так долго?

+0

Выбирает ли вид из вида длительное время? – sagi

+0

Нет, выбор '*' из 'last_30_days' происходит так же быстро, как и получается. – alexandernst

ответ

1

Большинство проблем здесь:

LEFT JOIN `CONSUMO` ON sub1.fecha = DATE_FORMAT(fechahora, "%M %e") 

В частности:

  • Не используйте LEFT; вы хотите, чтобы все строки, а не лишние, правильно? Так что используйте простой JOIN.

  • У индекса fechahora.

  • Не использовать DESCRIBE; он менее описателен, чем SHOW CREATE TABLE.

  • Вместо того, чтобы пересчитывать последние 30 дней снова и снова; иметь длинный стол с датами в течение нескольких лет и использовать предложение WHERE, чтобы ограничить нужные строки.

  • Не скрывать fechahora внутри функции. Перестановка запрос таким образом, это выглядит как

    ON fechahora> = ... sub1.fecha ... И fechahora < ... sub1.fecha + ИНТЕРВАЛ 1 ДЕНЬ ...

... должен быть тем, что требуется для выполнения инверсии «% M% e». Вероятно, вам лучше было бы изменить last_30_days, чтобы вычислить простой тип данных DATE. Если/когда вам нужно определенное форматирование на выходе, сделайте это в SELECT.

+0

Результат моего запроса, когда вы не используете 'left join', как вы предложили изменить (на самом деле он ничего не возвращает). Я сделал индекс на 'fechahora', но производительность по-прежнему точно такая же. 'last_30_days' уже вычисляет тип' DATE'. Что касается взгляда на таблицу, содержащую несколько лет, я не уверен, что это не является изящным способом ее выполнения или что это улучшит ситуацию, поскольку выбор из этого представления выполняется так же быстро, как выбор. – alexandernst

+0

Потратив еще несколько часов на это, я нашел корень проблемы. У вас есть точка в последнем, что вы сказали. Запрос занимает настолько много времени, потому что ему нужно преобразовать каждый столбец DATETIME в DATE. – alexandernst