SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 05.08.2010 10:18:12

Neval
Гуру
Откуда: Киев
Зарегистрирован: 11.03.2008
Сообщений: 449

Порядок выполнения многотабличного запроса

Ребят, подскажите-ка, выполняю запрос, который считает количество записей конкретного пользователя в заданном промежутке времени с разбивкой по дням:

SELECT
     SUM( `s`.`costs` ) ,
     DATE_FORMAT( `s`.`start_send_date` , '%d.%m.%Y' ) AS `date`
FROM
     `sms` AS `s`
LEFT JOIN
     `sms_numbers` AS `sn`
     ON
          `sn`.`sms_id` = `s`.`id`
WHERE
     `s`.`start_send_date` > '2010-07' AND
     `s`.`start_send_date` < '2010-08' AND
     `s`.`user_id` =4508 AND
     `s`.`type` <> 'deleted' AND
     `s`.`send_time` IS NULL AND
     `sn`.`status` = 'REJECTD'
GROUP BY
     `date`
 


EXPLAIN данного запроса:

id          select_type     table        type              possible_keys                  key         key_len          ref               rows            Extra
1             SIMPLE          sn           ref               status,sms_id                 status          1             const           900476           Using where; Using temporary; Using filesort
1             SIMPLE           s         eq_ref     PRIMARY,user_id,send_date    PRIMARY         4      route.sn.sms_id         1              Using where

Вот не могу понять почему он начинает поиск со второй таблицы. Всегда был уверен, что порядок поиска по таблицам идёт в том же порядке, что и указан в запросе и всегда главную таблицу ставил в "FROM".

И что же получается, оптимизатор выбирает самый короткий ключ? Это же нонсенс, чем короче ключ, тем больше он хранит ссылок на записи, а значит и дольше идёт выборка уже в найденных записях...

Добавил USE INDEX (`user_id`) для первой таблицы, теперь explain показывает что надо:

id          select_type     table        type          possible_keys           key      key_len          ref           rows        Extra
1             SIMPLE           s            ref              user_id              user_id        5            const        382648      Using where; Using temporary; Using filesort
1             SIMPLE          sn           ref           status,sms_id         sms_id        4          route.s.id         6          Using where

И запрос вместо 150 секунд выполняется всего 7 smile

И что теперь, для указания порядка и уверенности в правильных шагах использовать USE INDEX?


Человек без чувства юмора - не серьёзный человек wink

Неактивен

 

#2 05.08.2010 12:02:13

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Порядок выполнения многотабличного запроса

Не понятно, почему 7 секунд. В первом случае сканируется 900 476 строк, во втором —
2 295 888, что больше по крайней мере в два раза. Т.е. если оценки по количеству
строк правильные, то оптимизатор выбирает правильный план выполнения. Если оценки
не правильные — можно попробовать сделать OPTIMIZE TABLE — оно пересчитает cardi-
nality индексов, и будет выдавать более правдоподобные значения.

Неактивен

 

#3 05.08.2010 13:58:28

Neval
Гуру
Откуда: Киев
Зарегистрирован: 11.03.2008
Сообщений: 449

Re: Порядок выполнения многотабличного запроса

В первом случае выбираются 900 тысяч строк из 20 миллионов, а во втором из 3х миллионов.
Я понимаю так: в первом шаге определилось Х строк, потом смотрим другую таблицу по заданным условиям используя найденные записи первого шага. А связь s к sn идёт один ко многим, потому найти в первой таблице меньшее количество строк проще, чем бОльшее во второй.

Я, честно говоря, не совсем понимаю почему во втором шаге 6 написано. Дословно это что значит?

Оптимизацию попробую, может и правда мусора много мешается под ногами... Данных много, оптимизацию хоть бы раз в год кто-то запускал)))


Человек без чувства юмора - не серьёзный человек wink

Неактивен

 

#4 05.08.2010 14:20:48

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Порядок выполнения многотабличного запроса

Это значит, что MySQL ожидает получить из второй таблицы 6 строк на каждую
строку из первой таблицы.

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson