Оптимизация запросов MySQL - отличная, упорядоченная и ограниченная - PullRequest
1 голос
/ 27 мая 2010

Я пытаюсь оптимизировать следующий запрос:

select distinct this_.id as y0_
from Rental this_
    left outer join RentalRequest rentalrequ1_ 
      on this_.id=rentalrequ1_.rental_id
    left outer join RentalSegment rentalsegm2_ 
      on rentalrequ1_.id=rentalsegm2_.rentalRequest_id
where
    this_.DTYPE='B'
    and this_.id<=1848978
    and this_.billingStatus=1
    and rentalsegm2_.endDate between 1273631699529 and 1274927699529
order by rentalsegm2_.id asc
limit 0, 100;

Этот запрос выполняется несколько раз подряд для постраничной обработки записей (каждый раз с разным пределом). Он возвращает идентификаторы, которые мне нужны при обработке. Моя проблема в том, что этот запрос занимает более 3 секунд. У меня есть около 2 миллионов строк в каждой из трех таблиц.

Объясните дает:

+----+-------------+--------------+--------+-----------------------------------------------------+---------------+---------+--------------------------------------------+--------+----------------------------------------------+
| id | select_type | table        | type   | possible_keys                                       | key           | key_len | ref                                        | rows   | Extra                                        |
+----+-------------+--------------+--------+-----------------------------------------------------+---------------+---------+--------------------------------------------+--------+----------------------------------------------+
|  1 | SIMPLE      | rentalsegm2_ | range  | index_endDate,fk_rentalRequest_id_BikeRentalSegment | index_endDate | 9       | NULL                                       | 449904 | Using where; Using temporary; Using filesort | 
|  1 | SIMPLE      | rentalrequ1_ | eq_ref | PRIMARY,fk_rental_id_BikeRentalRequest              | PRIMARY       | 8       | solscsm_main.rentalsegm2_.rentalRequest_id |      1 | Using where                                  | 
|  1 | SIMPLE      | this_        | eq_ref | PRIMARY,index_billingStatus                         | PRIMARY       | 8       | solscsm_main.rentalrequ1_.rental_id        |      1 | Using where                                  | 
+----+-------------+--------------+--------+-----------------------------------------------------+---------------+---------+--------------------------------------------+--------+----------------------------------------------+

Я попытался удалить отчет, и запрос выполнялся в три раза быстрее. объяснение без запроса дает:

+----+-------------+--------------+--------+-----------------------------------------------------+---------------+---------+--------------------------------------------+--------+-----------------------------+
| id | select_type | table        | type   | possible_keys                                       | key           | key_len | ref                                        | rows   | Extra                       |
+----+-------------+--------------+--------+-----------------------------------------------------+---------------+---------+--------------------------------------------+--------+-----------------------------+
|  1 | SIMPLE      | rentalsegm2_ | range  | index_endDate,fk_rentalRequest_id_BikeRentalSegment | index_endDate | 9       | NULL                                       | 451972 | Using where; Using filesort | 
|  1 | SIMPLE      | rentalrequ1_ | eq_ref | PRIMARY,fk_rental_id_BikeRentalRequest              | PRIMARY       | 8       | solscsm_main.rentalsegm2_.rentalRequest_id |      1 | Using where                 | 
|  1 | SIMPLE      | this_        | eq_ref | PRIMARY,index_billingStatus                         | PRIMARY       | 8       | solscsm_main.rentalrequ1_.rental_id        |      1 | Using where                 | 
+----+-------------+--------------+--------+-----------------------------------------------------+---------------+---------+--------------------------------------------+--------+-----------------------------+

Как видите, Using temporary добавляется при использовании различных.

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

Большое спасибо!

Редактировать: я попытался упорядочить по this_.id, как предложено, и запрос был в 5 раз медленнее Вот план объяснения:

+----+-------------+--------------+------+-----------------------------------------------------+---------------------------------------+---------+------------------------------+--------+----------------------------------------------+
| id | select_type | table        | type | possible_keys                                       | key                                   | key_len | ref                          | rows   | Extra                                        |
+----+-------------+--------------+------+-----------------------------------------------------+---------------------------------------+---------+------------------------------+--------+----------------------------------------------+
|  1 | SIMPLE      | this_        | ref  | PRIMARY,index_billingStatus                         | index_billingStatus                   | 5       | const                        | 782348 | Using where; Using temporary; Using filesort | 
|  1 | SIMPLE      | rentalrequ1_ | ref  | PRIMARY,fk_rental_id_BikeRentalRequest              | fk_rental_id_BikeRentalRequest        | 9       | solscsm_main.this_.id        |      1 | Using where; Using index; Distinct           | 
|  1 | SIMPLE      | rentalsegm2_ | ref  | index_endDate,fk_rentalRequest_id_BikeRentalSegment | fk_rentalRequest_id_BikeRentalSegment | 8       | solscsm_main.rentalrequ1_.id |      1 | Using where; Distinct                        | 
+----+-------------+--------------+------+-----------------------------------------------------+---------------------------------------+---------+------------------------------+--------+----------------------------------------------+

Ответы [ 3 ]

2 голосов
/ 27 мая 2010
  1. Из плана выполнения мы видим, что оптимизатор достаточно умен, чтобы понимать, что здесь вам не нужны ВНЕШНИЕ СОЕДИНЕНИЯ. В любом случае, вам лучше указать это явно.
  2. Модификатор DISTINCT означает, что вы хотите сгруппировать все поля в части SELECT, то есть ORDER BY всех указанных полей, а затем удалить дубликаты. Другими словами, предложение order by rentalsegm2_.id asc здесь не имеет смысла.

Запрос ниже должен вернуть эквивалентный результат:

select distinct this_.id as y0_
from Rental this_
    join RentalRequest rentalrequ1_ 
      on this_.id=rentalrequ1_.rental_id
    join RentalSegment rentalsegm2_ 
      on rentalrequ1_.id=rentalsegm2_.rentalRequest_id
where
    this_.DTYPE='B'
    and this_.id<=1848978
    and this_.billingStatus=1
    and rentalsegm2_.endDate between 1273631699529 and 1274927699529
limit 0, 100;

UPD

Если вы хотите, чтобы план выполнения начинался с RentalSegment, вам необходимо добавить следующие индексы в базу данных:

  1. RentalSegment (endDate)
  2. RentalRequest (id, rental_id)
  3. Прокат (id, DTYPE, billingStatus) или (id, billingStatus, DTYPE)

Затем запрос можно переписать следующим образом:

SELECT this_.id as y0_
FROM RentalSegment rs
    JOIN RentalRequest rr
    JOIN Rental this_
WHERE rs.endDate between 1273631699529 and 1274927699529
    AND rs.rentalRequest_id = rr.id
    AND rr.rental_id <= 1848978
    AND rr.rental_id = this_.id
    AND this_.DTYPE='D'
    AND this_.billingStatus = 1
GROUP BY this_.id
LIMIT 0, 100;

Если план выполнения не начнется с RentalSegment, вы можете ввести STRAIGHT_JOIN.

2 голосов
/ 27 мая 2010

Причина того, что запрос без отчетливого выполнения выполняется быстрее, заключается в том, что у вас есть предложение limit. Без отчетливого серверу нужно только посмотреть первые сто совпадений. Однако, однако, некоторые из этих строк могут иметь повторяющиеся поля, поэтому, если вы введете отдельное предложение, сервер должен просмотреть еще много строк, чтобы найти те, которые не имеют повторяющихся значений.

Кстати, почему вы используете OUTER JOIN?

1 голос
/ 27 мая 2010

Здесь для таблицы "rentalsegm2_» оптимизатор выбрал индекс «index_endDate», и его количество строк, ожидаемое от этой таблицы, составляет около 4,5 лакхов. Поскольку существуют другие условия, в которых существуют условия, вы можете проверить наличие табличных индексов "this_". Я имею в виду, что вы можете проверить в таблице "this_", сколько записей затронуто для каждого условия.

Таким образом, вы можете попробовать альтернативные решения, изменив индексы, используемые оптимизатором. Это можно получить с помощью команд «USE INDEX», «FORCE INDEX».

Спасибо

Ринсон К.Е. администратор базы данных www.qburst.com

...