воскресенье, 2 мая 2010 г.

mysql-slow-queries-username-and-post

Занимаясь настройкой и оптимизацией MySQL сервера, я как-то включил лог медленных запросов. Через несколько часов я обнаружил в логе следующий запрос.
SELECT
post.postid,
post.pagetext,
Ifnull(
user.username, post.username) AS username,
dateline
FROM post AS post
LEFT JOIN user AS
user
ON ( user.userid = post.userid )
WHERE threadid = 12511
AND visible = 1
ORDER BY dateline ASC
LIMIT 3750, 250;

Судя по логу, этот запрос выполнялся более 8 секунд
# Query_time: 8.245419 Lock_time: 0.000153 Rows_sent: 250 Rows_examined: 20688

Прогон того же запроса на машине разработчика (без живой нагрузки) дал время выполнения 0.072 секунды.
mysql> SELECT COUNT(*) FROM post;
+----------+
| COUNT(*) |
+----------+
| 475225 |
+----------+
Судя по тому, что выборка затронула
20688 строк данных, делаю вывод, что операцией LEFT JOIN была выполнена склейка всех записей таблицы post с записями таблицы user, после чего было выполнено отсечение 250 строк.
Вглядевшись в запрос повнимательнее, я решил, что рациональнее сначала выбрать нужные 250 строк, и только потом производить склейку.
Хочу заметить, что операция склейки LEFT JOIN не изменяет количество выбранных из таблицы post записей, так как поле userid таблицы user является первичным ключом и поэтому уникально.
Итак, оптимизированный запрос будет выглядеть так:
SELECT post.postid,
post.pagetext,
Ifnull(USER.username, post.username) AS username,
dateline
FROM (SELECT postid,
pagetext,
username,
dateline,
userid
FROM post
WHERE threadid = 12511
AND visible = 1
ORDER BY dateline ASC
LIMIT 3750, 250) AS post
LEFT JOIN USER AS USER
ON ( USER.userid = post.userid );
Время выполнения запроса на тестовой машине - 0.008 сек.
Экономия - в 9 раз.