Оптимизация SQL-запросов во избежание временной таблицы
Таблица:
CREATE TABLE `T1` (
`UserId` int(10) unsigned NOT NULL,
`FriendUserId` int(10) unsigned NOT NULL,
`IsDisplayed` tinyint(1) unsigned NOT NULL,
`Created` datetime NOT NULL,
KEY `FriendUserId` (`FriendUserId`,`IsDisplayed`,`UserId`,`Created`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Запрос:
SELECT `UserId`, `FriendUserId`, UNIX_TIMESTAMP(`Created`) AS `Created`
FROM `T1` WHERE `FriendUserId` = 22
AND `IsDisplayed` = 0
GROUP BY `UserId`
ORDER BY `Created`
Результат EXPLAIN:
id: 1
select_type: SIMPLE
table: T1
type: ref
possible_keys: FriendUserId
key: FriendUserId
key_len: 5
ref: const,const
rows: 1
Extra: Using where; Using index; Using temporary; Using filesort
Вопрос:
Как я могу оптимизировать его, чтобы временная таблица не использовалась?
Ответы
Ответ 1
Как вы, вероятно, понимаете, проблема в том, что GROUP BY
заказывает данные по UserId
, но приведенный набор должен быть упорядочен Created
; Таким образом, MySQL ставит вывод во временную таблицу, сортирует ее и выводит.
Трюк может заключаться в том, чтобы принудительно выдавать отдельные строки в порядке Created
сразу.
Первое, что приходит мне на ум, это что-то вроде этого:
SELECT DISTINCT
UserId,
FriendUserId,
UNIX_TIMESTAMP(`Created`) AS `Created`
FROM T1
WHERE FriendUserId = 22 AND IsDisplayed = 0
ORDER BY `Created`
и измените индекс на (FriendUserId, IsDisplayed, Created, UserId)
.
Или другой запрос с тем же индексом:
SELECT
UserId,
FriendUserId,
UNIX_TIMESTAMP(`Created`) AS `Created`
FROM T1
WHERE FriendUserId = 22 AND IsDisplayed = 0
GROUP BY `Created`, UserId
Ответ 2
MySQL документация говорит:
Временные таблицы могут создаваться в таких условиях, как:
Если существует предложение ORDER BY
и другое предложение GROUP BY
или если ORDER BY
или GROUP BY
содержит столбцы из таблиц, отличных от первая таблица в очереди присоединения, создается временная таблица.
Таким образом, вы можете избежать использования временной таблицы только путем удаления order by Created