Предположим, у меня есть следующие таблицы:
CREATE TABLE Game (
GameID INT UNSIGNED NOT NULL,
GameType TINYINT UNSIGNED NOT NULL,
PRIMARY KEY (GameID),
INDEX Index_GameType (GameType, GameID)
) ENGINE=INNODB
CREATE TABLE HighScore (
Game INT UNSIGNED NOT NULL,
Score SMALLINT UNSIGNED,
PRIMARY KEY (Game),
INDEX Index_Score (Score, Game),
CONSTRAINT Constr_Score_Game_fk
FOREIGN KEY Score_Game_fk (Game) REFERENCES Game (GameID)
) ENGINE=INNODB
(Это уменьшенные версии реальных таблиц, с которыми я работаю. В реальных таблицах больше столбцов и индексов. Вышеприведенные таблицы отражают основные особенности ситуации.)
(Предполагается, что число различных GameTypes невелико, поэтому индекс Index_GameType не очень избирателен.)
Предположим, я запускаю следующий запрос:
SELECT
HighScore.Score
FROM
HighScore
JOIN Game ON HighScore.Game = Game.GameID
WHERE
Game.GameType = 42
ORDER BY
HighScore.Score DESC
LIMIT 50
Глядя на этот запрос и структуру таблицы, мы, вероятно, можем согласиться с тем, что разумно было бы сканировать таблицу HighScore и объединять строки, пока не будет найдено 50, для которых выполняется условие WHERE. Тем не менее, EXPLAIN для меня показал (используя мои настоящие, более сложные таблицы), что MySQL фактически планирует искать все строки в Game, удовлетворяющие условию WHERE, объединять их с HighScore и выполнять сортировку файлов, чтобы получить строки в отсортированном порядке. 1011 *
Казалось бы, разумно указать вместо STRAIGHT_JOIN в приведенном выше запросе. Теперь вывод EXPLAIN указывает, что первая таблица, HighScore, «использует индекс» (как и ожидалось), но число строк, о которых сообщается, представляется количеством строк в таблице HighScore. Должен ли я считать, что это означает, что MySQL планирует взять практически весь индекс, объединить каждую строку в этом индексе с другой таблицей и только затем выбросить строки ниже 50 лучших? Это кажется смешным, но я не уверен, что так оно и будет на самом деле. У кого-нибудь есть идеи?