MySQL在指定了ORDER BY和LIMIT并且实际上只需要连接少量行的连接情况下是如何工作的?
假设我有以下表格:MySQL在指定了ORDER BY和LIMIT并且实际上只需要连接少量行的连接情况下是如何工作的?,mysql,join,indexing,sql-order-by,Mysql,Join,Indexing,Sql Order By,假设我有以下表格: 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,
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
(这些是我正在使用的真实表的精简版本。真实表有更多的列和索引。上面的表捕获了这种情况的基本特征。)
(不同游戏类型的数量应该假设很小,因此索引_游戏类型不是很有选择性。)
假设我运行以下查询:
SELECT
HighScore.Score
FROM
HighScore
JOIN Game ON HighScore.Game = Game.GameID
WHERE
Game.GameType = 42
ORDER BY
HighScore.Score DESC
LIMIT 50
看看这个查询和表设计,我们可能会同意,明智的做法是向下扫描HighScore表并连接行,直到找到满足WHERE条件的50行。然而,一个解释告诉我(使用我真实的、更复杂的表),MySQL实际上计划在游戏中查找满足WHERE条件的所有行,使用HighScore连接这些行,并进行文件排序以获得按排序顺序排列的行
因此,在上面的查询中指定一个直连接似乎是明智的。现在解释输出表明第一个表HighScore正在“使用索引”(正如预期的那样),但报告的行数似乎是HighScore表中的行数。我是否应该认为这意味着MySQL计划从本质上获取整个索引,将该索引中的每一行连接到另一个表,然后只丢弃前50行以下的行?这似乎很荒谬,但我不确定它是否真的会这样做。有人知道吗?由于要筛选和排序的字段位于不同的表中,因此它们不能由单个索引覆盖 如果您添加一个
stright\u JOIN
子句,您将强制MySQL
从HighScore
中获取每条记录(使用Score
上的索引),在游戏中找到匹配的记录,检查它是否为42
,然后返回(或忽略)它
由于MySQL
无法预先判断匹配的记录数,因此它将假设最差的记录数,只显示计划中HighScore
记录的总数
实际上,查询将在返回50
匹配记录后停止。此答案扩展了Quassnoi提供的信息。为了有更多的空间,我使用答案而不是评论
按照Quassnoi的建议,我测试了使用和不使用LIMIT子句运行查询。因为我使用的是InnoDB而不是MyISAM,所以我使用以下查询来获取读取请求的数量:
select
variable_value
from
information_schema.GLOBAL_STATUS
where
variable_name = 'innodb_buffer_pool_read_requests';
在运行任何查询之前,这给出了87131。在运行没有LIMIT子句的查询之后,它给出了170381。在使用LIMIT子句运行查询之后,它给出了175315
因此,无限制查询中涉及的读取请求数似乎为170381-87131=83250,而有限制查询中涉及的读取请求数似乎为175315-170381=4934。重复实验时出现的数字大致相同。这些数字似乎与行没有对应关系,事实上,我不确定它们在获取的数据方面对应的是什么*,但它们确实表明,在添加限制查询时,从磁盘获取的数据可验证地更少。因此,我倾向于认为Quassnoi是正确的,MySQL确实使用了一种合理的策略来获取有限的行数
- 无限制查询中涉及的读取请求数大约是另一个查询的17倍,但返回的结果远远超过17*50,因此它似乎与结果数没有直接对应
这正是我所希望的情况。你能给我指一下任何证明MySQL会这么做的文档吗?@Hammerite:这没有文档,但是你可以通过比较key\u read\u请求
来检查是否有LIMIT
子句(当然是在MyISAM
中)的查询。