Mysql:indexes 和 table 中的行顺序
Mysql:indexes and order of rows in a table
第 1 步:
我正在创建一个简单的 table。
CREATE TABLE `indexs`.`table_one` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45) NULL,
PRIMARY KEY (`id`));
第 2 步:
我在其中插入了两个 table。
insert into table_one (name) values ("B");
insert into table_one (name) values ("A");
第 3 步:
我做了一个select,我得到一个table,其中的记录是按id排序的
SELECT * FROM table_one;
这是预期的结果,因为在mysql中主键是聚集索引,因此数据将按其物理排序。
现在是我不明白的部分。
第 4 步:
我正在名称列上创建索引。
CREATE INDEX index_name ON table_one(name)
我再次重复第 3 步,但得到了不同的结果。这些行现在根据名称列排序。
为什么会这样?为什么 table 中的行顺序会根据 name 列上的新索引发生变化,因为据我了解,在 mysql 中,主键是唯一的聚集索引,并且所有额外创建的索引是次要的。
I make a select, I get a table, the records in which are ordered by id. [...] This is the expected result, because in mysql the primary key is a clustered index, therefore the data will be physically ordered by it.
这里对一个概念有些误解
Table 行没有固有的顺序:它们代表 无序的 行集。虽然聚簇索引强制对存储中的数据进行物理排序,但它不能保证 select
查询 return 行的顺序。
如果您希望对查询结果进行排序,请使用 order by
子句。如果没有这样的子句,排序或行是 undefined:数据库可以自由地 return 结果以任何它喜欢的顺序,并且不保证结果在连续执行中是一致的相同的查询。
select * from table_one order by id;
select * from table_one order by name;
(专线小巴解释最多)
Why is this happening? why the order of the rows in the table changes in accordance with the new index on the name column
使用 EXPLAIN SELECT ...
-- 它可能会提示我要提出的建议。
您添加了 INDEX(name)
。在 InnoDB 中,PRIMARY KEY
列被附加到每个二级索引的末尾。所以它实际上是一个按 (name,id)
排序并且只包含这些列的 BTree。
现在,优化器可以自由地从索引中获取数据,因为它具有您要求的所有内容(id 和名称)。 (这个指标叫做“覆盖”。)
由于您没有指定 ORDER BY
,结果集排序有效(请参阅 GMB 的讨论)。
故事的寓意: 如果您想要排序,请指定 ORDER BY
。 (如果优化器可以在不进行排序的情况下了解如何提供数据,那么它就足够聪明,可以“不做额外的工作”。
进一步实验:向 table 添加另一列,但不要更改索引。现在您会发现 SELECT * FROM t
的排序与 SELECT id, name FROM t
不同。我想我已经给了你足够的线索来预测这种差异,如果没有,请问。
第 1 步:
我正在创建一个简单的 table。
CREATE TABLE `indexs`.`table_one` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45) NULL,
PRIMARY KEY (`id`));
第 2 步:
我在其中插入了两个 table。
insert into table_one (name) values ("B");
insert into table_one (name) values ("A");
第 3 步:
我做了一个select,我得到一个table,其中的记录是按id排序的
SELECT * FROM table_one;
这是预期的结果,因为在mysql中主键是聚集索引,因此数据将按其物理排序。
现在是我不明白的部分。
第 4 步:
我正在名称列上创建索引。
CREATE INDEX index_name ON table_one(name)
我再次重复第 3 步,但得到了不同的结果。这些行现在根据名称列排序。
为什么会这样?为什么 table 中的行顺序会根据 name 列上的新索引发生变化,因为据我了解,在 mysql 中,主键是唯一的聚集索引,并且所有额外创建的索引是次要的。
I make a select, I get a table, the records in which are ordered by id. [...] This is the expected result, because in mysql the primary key is a clustered index, therefore the data will be physically ordered by it.
这里对一个概念有些误解
Table 行没有固有的顺序:它们代表 无序的 行集。虽然聚簇索引强制对存储中的数据进行物理排序,但它不能保证 select
查询 return 行的顺序。
如果您希望对查询结果进行排序,请使用 order by
子句。如果没有这样的子句,排序或行是 undefined:数据库可以自由地 return 结果以任何它喜欢的顺序,并且不保证结果在连续执行中是一致的相同的查询。
select * from table_one order by id;
select * from table_one order by name;
(专线小巴解释最多)
Why is this happening? why the order of the rows in the table changes in accordance with the new index on the name column
使用 EXPLAIN SELECT ...
-- 它可能会提示我要提出的建议。
您添加了 INDEX(name)
。在 InnoDB 中,PRIMARY KEY
列被附加到每个二级索引的末尾。所以它实际上是一个按 (name,id)
排序并且只包含这些列的 BTree。
现在,优化器可以自由地从索引中获取数据,因为它具有您要求的所有内容(id 和名称)。 (这个指标叫做“覆盖”。)
由于您没有指定 ORDER BY
,结果集排序有效(请参阅 GMB 的讨论)。
故事的寓意: 如果您想要排序,请指定 ORDER BY
。 (如果优化器可以在不进行排序的情况下了解如何提供数据,那么它就足够聪明,可以“不做额外的工作”。
进一步实验:向 table 添加另一列,但不要更改索引。现在您会发现 SELECT * FROM t
的排序与 SELECT id, name FROM t
不同。我想我已经给了你足够的线索来预测这种差异,如果没有,请问。