Оптимизация ORDER BY в запросах с джоинами

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

Маленькая выдержка из мануалов по оптимизации:

===
Как MySQL оптимизирует ORDER BY
Ниже приведены некоторые случаи, когда MySQLне может использовать индексы, чтобы выполнить ORDER BY

Связываются несколько таблиц, и столбцы, по которым делается
сортировка ORDER BY, относятся не только к первой неконстантной
(const) таблице, используемой для выборки строк(это первая таблица
в выводе EXPLAIN, в которой не используется константный, const, метод выборки строк).

===

Для ORDER BY важно, чтобы таблица, по которой будет производиться сортировка была на первом месте. Однако по умолчанаю, в каком бы порядке вы не джойнили таблицы, встроенный в mysql оптимизатор переставит их в том порядке, как он сам посчитает нужным. То есть если вы поставили нужную таблицу первой в запросе, то это вовсе не означает, что она будет на самом деле первой.

К счастью, оптимизатору mysql можно сказать, чтобы он джоинил таблицы в том порядке, какой мы ему указали, для этого нужно в SELECT добавить команду STRAIGHT_JOIN:

SELECT STRAIGHT_JOIN… FROM table JOIN…… ORDER BY table.row

Проверка на mysql базе форума PHPBB3 содержащей около 300 000 постов:

SELECT t.*, p.*, u.username
FROM phpbb3_topics as t, phpbb3_posts as p,  phpbb3_users as u
WHERE t.topic_replies>0 AND p.poster_id=u.user_id AND topic_first_post_id<>p.post_id AND topic_approved=1 AND p.topic_id=t.topic_id AND t.forum_id='16' AND p.post_id<'244103'
ORDER by post_id desc LIMIT 40

Query took 12.2571 sec

в explain видим ужасное: Using where; Using temporary; Using filesort

Меняем порядок таблиц (кеш мускуля сбросил перезагрузкой):

SELECT STRAIGHT_JOIN t.*, p.*, u.username
FROM phpbb3_posts as p, phpbb3_topics as t, phpbb3_users as u
WHERE t.topic_replies>0 AND p.poster_id=u.user_id AND topic_first_post_id<>p.post_id AND topic_approved=1 AND p.topic_id=t.topic_id AND t.forum_id='13' AND p.post_id<'234103'
ORDER by post_id desc LIMIT 40

Query took 0.0447 sec

в explain: Using where; 

Вот такой принудительной перестановкой таблиц мы ускорили выполнение запроса в 300 раз!

Это совсем не значит, что нужно всегда использовать STRAIGHT_JOIN и самому следить за порядком таблиц. Но в некоторых случах это необходимо.