Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySQL在指定了ORDER BY和LIMIT并且实际上只需要连接少量行的连接情况下是如何工作的?_Mysql_Join_Indexing_Sql Order By - Fatal编程技术网

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
中)的查询。