Странное время выполнения MySQL SELECT - PullRequest
1 голос
/ 03 ноября 2010

Мне трудно понять, почему время выполнения похожих запросов так сильно отличается друг от друга. У меня есть простой SELECT запрос, подобный этому:

SELECT
    `location_id`,
    `datetime`,
    `year`,
    `month`,
    `load`
FROM  load_report_rows
WHERE location_id = '16583'
AND   load_report_id = '1'
AND   year = '2010'

Этот запрос выполняется в течение 0,1837 секунд, но если я изменю location_id на «18260», запрос внезапно займет 2,7012 секунды. Все три поля, которые используются в предложении WHERE, проиндексированы, и оба запроса возвращают ровно 8760 строк. EXPLAIN для этого запроса возвращает следующую информацию:

id               1
select_type      SIMPLE
table            load_report_rows
type             index_merge
possible_keys    load_report_id,location_id,year
key              location_id,load_report_id,year
key_len          4,4,4
ref              NULL
rows             3349
extra            using intersect(location_id,load_report_id,year); using where

Профилировщик запросов MySQL выдает следующее для каждого запроса:

+--------------------------------+----------+----------+
| Status                         | Query 1  | Query 2  |
+--------------------------------+----------+----------+
| starting                       | 0.000023 | 0.000023 |
| checking query cache for query | 0.000072 | 0.000068 |
| checking permissions           | 0.000010 | 0.000068 |
| opening tables                 | 0.000012 | 0.000012 |
| system lock                    | 0.000005 | 0.000004 |
| table lock                     | 0.000008 | 0.000008 |
| init                           | 0.000050 | 0.000026 |
| optimizing                     | 0.000030 | 0.000014 |
| statistics                     | 0.000461 | 0.001048 |
| preparing                      | 0.000022 | 0.000043 |
| executing                      | 0.000003 | 0.000004 |
| sending data                   | 0.100939 | 2.649942 |
| end                            | 0.000013 | 0.000040 |
| end                            | 0.000004 | 0.000004 |
| query end                      | 0.000004 | 0.000004 |
| freeing items                  | 0.000012 | 0.000013 |
| closing tables                 | 0.000008 | 0.000008 |
| logging slow query             | 0.000002 | 0.000003 |
| cleaning up                    | 0.000006 | 0.000005 |
+--------------------------------+----------+----------+

Этап sending data значительно дольше выполняется со вторым запросом. Какие шаги включены в это? Вот структура таблицы для соответствующих полей, если это помогает:

`id`              int(11)
`load_report_id`  int(11)
`location_id`     int(11)
`datetime`        datetime
`year`            int(4)
`month`           int(2)
`load`            decimal(16,8)

PRIMARY KEY  (`id`)
KEY `load_report_id` (`load_report_id`)
KEY `location_id` (`location_id`)
KEY `year` (`year`)
KEY `month` (`month`)

Есть идеи, что может заставить второй запрос выполняться так медленно?

Ответы [ 4 ]

2 голосов
/ 03 ноября 2010

sending data вводит в заблуждение описание. На самом деле оно включает и время, потраченное на выполнение запроса , и время, потраченное на отправку результата по сети. источник 1 источник 2 источник 3

Поскольку оба запроса генерируют примерно одинаковый объем данных, разница должна быть на стадии выполнения. Есть несколько возможностей:

  • Возможно, эти три индекса не генерируют полезное пересечение в правильном порядке, когда location_id равен 18260. Попробуйте добавить индекс из нескольких столбцов, как предложил @Ike Walker.

  • Возможно, строки, возвращаемые во втором запросе, фрагментированы по всему диску. Это заставило бы MySQL тратить значительное количество времени на ожидание поиска диска в следующем месте. Попробуйте оптимизировать свой стол. Фрагментация также может происходить с интенсивно используемыми индексами, поэтому попробуйте удалить и заново создать некоторые индексы.

1 голос
/ 03 ноября 2010

Я думаю, что будет кеширование. Вы заставляете MySQL кастовать / конвертировать ваши значения (строки / числа). Все поля, по которым вы ищете, являются int, но вы передаете mysql строку для поиска. Удалите кавычки вокруг чисел, по которым вы ищете, и посмотрите, что произойдет.

MySQL может преобразовывать все значения в таблице в строки для сравнения вместо преобразования строки поиска в число. Вы отправили только 1 запрос объяснения, вы должны опубликовать оба, чтобы увидеть, отличаются ли пути выполнения.

1 голос
/ 03 ноября 2010

У меня есть пара предложений.

Во-первых, я бы добавил индекс из нескольких столбцов, чтобы охватить эти 3 столбца.Таким образом, вы можете сканировать отдельный индекс, а не выполнять его объединение:

ALTER TABLE load_report_rows
  ADD KEY location_report_year_idx (location_id,load_report_id,year);

Новый индекс делает индекс location_id несколько избыточным, поэтому вы можете рассмотреть возможность его удаления.* Во-вторых, я бы порекомендовал переписать запрос, чтобы вводить целые числа как целые, а не как строки.Это позволит избежать ненужного неявного преобразования типов, которое может привести к снижению производительности.Вероятно, это не является причиной вашей конкретной проблемы, но я думаю, что это хорошая практика в целом:

SELECT
    `location_id`,
    `datetime`,
    `year`,
    `month`,
    `load`
FROM  load_report_rows
WHERE location_id = 16583
AND   load_report_id = 1
AND   year = 2010
0 голосов
/ 03 ноября 2010

Состояние sending data относится к тому моменту, когда MySQL фактически отправляет данные по сети.Так что медлительность вполне может быть связана с тем, что id 18260 просто возвращает намного больше строк, чем ваш первый запрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...