MySQL Slow Query Анализ и индексирование - PullRequest
0 голосов
/ 22 октября 2009

Недавно мы заметили, что конкретный запрос появляется в наших медленных журналах запросов, занимающих довольно много времени. Я проанализировал это в меру своих возможностей, но не могу понять на всю жизнь, почему это занимает так много времени, и почему настроенные нами индексы не используются.

Вот упрощенная (т. Е. Читаемая) версия запроса для примера:

SELECT processstage.id AS processstage_id, 
  processstage.job_id AS processstage_job_id, 
  processstage.event_id AS processstage_event_id, ...
FROM processstage INNER JOIN jobevent ON jobevent.id = processstage.event_id 
WHERE processstage.due_date <= '2009-10-28 16:07:59' AND (EXISTS (
  SELECT 1 FROM job 
  WHERE jobevent.job_id = job.id AND job.brand_id = 1
)) ORDER BY processstage.due_date;

Кроме того, для правильного измерения важно отметить размер таблицы, processstage:

mysql> SELECT COUNT(id) FROM processstage;
+-----------+
| COUNT(id) |
+-----------+
|    596183 | 
+-----------+

Когда я запускаю EXPLAIN для запроса, я обнаруживаю, что таблица processstage читает более огромное количество строк (см. «Использование где; Использование файловой сортировки»), поскольку индекс не используется (что Я могу сказать):

mysql> EXPLAIN SELECT processstage.id AS processstage_id, processstage.job_id AS processstage_job_id, processstage.event_id AS processstage_event_id     FROM processstage INNER JOIN jobevent ON jobevent.id = processstage.event_id      WHERE processstage.due_date <= '2009-10-28 16:07:59' AND (EXISTS (SELECT 1      FROM job      WHERE jobevent.job_id = job.id AND job.brand_id = 1)) ORDER BY processstage.due_date;
+----+--------------------+--------------+--------+---------------------------------------------------+---------+---------+------------------------------+--------+-----------------------------+
| id | select_type        | table        | type   | possible_keys                                     | key     | key_len | ref                          | rows   | Extra                       |
+----+--------------------+--------------+--------+---------------------------------------------------+---------+---------+------------------------------+--------+-----------------------------+
|  1 | PRIMARY            | processstage | ALL    | ix_processstage_due_date,processstage_event_id_fk | NULL    | NULL    | NULL                         | 606045 | Using where; Using filesort | 
|  1 | PRIMARY            | jobevent     | eq_ref | PRIMARY                                           | PRIMARY | 4       | processstage.event_id |      1 | Using where                 | 
|  2 | DEPENDENT SUBQUERY | job          | eq_ref | PRIMARY,ix_job_brand_id                           | PRIMARY | 4       | jobevent.job_id       |      1 | Using where                 | 
+----+--------------------+--------------+--------+---------------------------------------------------+---------+---------+------------------------------+--------+-----------------------------+
3 rows in set (0.00 sec)

Как ни странно, у нас есть индексы для столбцов, используемых в предложении WHERE запроса:

mysql> SHOW INDEXES FROM processstage;
+--------------+------------+----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table        | Non_unique | Key_name                   | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------------+------------+----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| processstage |          0 | PRIMARY                    |            1 | id          | A         |      614150 |     NULL | NULL   |      | BTREE      |         | 
| processstage |          1 | ix_processstage_job_id     |            1 | job_id      | A         |       47242 |     NULL | NULL   | YES  | BTREE      |         | 
| processstage |          1 | ix_processstage_stop_date  |            1 | stop_date   | A         |      614150 |     NULL | NULL   | YES  | BTREE      |         | 
| processstage |          1 | ix_processstage_order      |            1 | order       | A         |          16 |     NULL | NULL   | YES  | BTREE      |         | 
| processstage |          1 | ix_processstage_start_date |            1 | start_date  | A         |      122830 |     NULL | NULL   | YES  | BTREE      |         | 
| processstage |          1 | ix_processstage_milestone  |            1 | milestone   | A         |       12794 |     NULL | NULL   | YES  | BTREE      |         | 
| processstage |          1 | ix_processstage_due_date   |            1 | due_date    | A         |       51179 |     NULL | NULL   | YES  | BTREE      |         | 
| processstage |          1 | ix_processstage_process_id |            1 | process_id  | A         |       76768 |     NULL | NULL   | YES  | BTREE      |         | 
| processstage |          1 | processstage_event_id_fk   |            1 | event_id    | A         |        3722 |     NULL | NULL   | YES  | BTREE      |         | 
+--------------+------------+----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

Есть идеи, почему наши индексы, похоже, не используются? Возможно, я упускаю что-то очень очевидное или подхожу к этому совершенно неправильно. Любой вклад или предложение очень ценится!

Ответы [ 3 ]

1 голос
/ 22 октября 2009

попробуйте использовать USE INDEX. если mysql решит, что ему нужно прочитать определенную часть таблицы, он прибегнет к сканированию таблицы. с помощью USE INDEX вы говорите mysql, что сканирование таблиц стоит очень дорого.

1 голос
/ 22 октября 2009

Сколько рабочих мест вы получаете, где job.brand = 1? Если это разумная сумма, вы можете попробовать следующие запросы, чтобы облегчить некоторые объединения и подзапрос.

Первый запрос:

select distinct jobevent.id from jobevent
inner join job on job.id = jobevent.job_id
where job.brand = 1

с последующим

select processstage.id as processstage_id, 
  processstage.job_id as processstage_job_id, 
  processstage.event_id as processstage_event_id, ...
from processstage 
where processstage.due_date <= '2009-10-28 16:07:59' and 
processstage.event_id in (list of event ids from the previous query) 
order by processstage.due_date;

Предыдущие мысли:

Вы пытались выполнять регулярное объединение с заданиями вместо зависимого подзапроса? Что-то вроде:

SELECT processstage.id AS processstage_id, 
  processstage.job_id AS processstage_job_id, 
  processstage.event_id AS processstage_event_id, ...
FROM processstage 
INNER JOIN jobevent ON jobevent.id = processstage.event_id 
INNER JOIN job ON job.id = jobevent.job_id 
WHERE processstage.due_date <= '2009-10-28 16:07:59' AND 
job.brand = 1 
ORDER BY processstage.due_date;

Есть ли у вас мероприятия, в которых нет работы?

0 голосов
/ 22 октября 2009

Некоторые идеи:

  • Выполните явное преобразование типа из строки '2009-10-28 16:07:59' в дату. Что может произойти сейчас, так это то, что ваш processstage.due_date преобразуется в строки перед сравнением. Выполнение преобразования типов (не уверен насчет systax в MySQL, но должно быть что-то вроде CAST (<your date string> as DATE) поможет оптимизатору разобраться в использовании индекса.
  • Сколько записей соответствует условию даты? Если большая часть таблицы соответствует условию или индекс не очень избирателен, использование индекса может быть бесполезным.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...