Mysql:表中的索引和行顺序

问题描述 投票:0回答:2

步骤1:

我正在创建一个简单的表格。

CREATE TABLE `indexs`.`table_one` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(45) NULL,
  PRIMARY KEY (`id`));

第2步:

我在该表中插入了两次内容。

insert into table_one (name) values ("B");
insert into table_one (name) values ("A");

步骤3:

我进行选择,得到一个表,其中的记录按 id 排序。

SELECT * FROM table_one;

这是预期的结果,因为在mysql中主键是聚集索引,因此数据将通过它进行物理排序。

现在我不明白的部分。

第四步:

我正在名称列上创建索引。

CREATE INDEX index_name ON table_one(name)

我再次重复步骤3,但得到了不同的结果。这些行现在根据名称列进行排序。

为什么会发生这种情况?为什么表中行的顺序会根据名称列上的新索引而变化,因为据我了解,在mysql中,主键是唯一的聚集索引,所有额外创建的索引都是辅助索引。

mysql sql indexing sql-order-by sql-insert
2个回答
3
投票

我进行选择,得到一个表,其中的记录按 id 排序。 [...]这是预期的结果,因为在mysql中主键是聚集索引,因此数据将通过它进行物理排序。

这里对一个概念有一些误解。

表行没有固有的顺序:它们代表无序的行集。虽然聚集索引强制存储中数据的物理顺序,但它不能保证

select
查询返回行的顺序。

如果您希望查询结果排序,请使用

order by
子句。如果没有这样的子句,排序或行是未定义的:数据库可以自由地按照它喜欢的任何顺序返回结果,并且不能保证结果在连续执行同一查询时保持一致。

select * from table_one order by id;
select * from table_one order by name;

3
投票

(GMB 解释最多)

为什么会发生这种情况?为什么表中的行顺序会根据名称列上的新索引而变化

使用

EXPLAIN SELECT ...
——它可能会提供我要建议的线索。

您添加了

INDEX(name)
。在 InnoDB 中,
PRIMARY KEY
列被附加到每个二级索引的末尾。所以它实际上是一个按
(name,id)
排序的 BTree,并且只包含那些列。

现在,优化器可以自由地从索引中获取数据,因为它拥有您要求的所有内容(id 和名称)。 (这个指标称为“覆盖”。)

由于您没有指定

ORDER BY
,因此结果集排序有效(请参阅 GMB 的讨论)。

故事寓意:如果您想要订购,请指定

ORDER BY
。 (如果优化器能够了解如何在不进行额外排序的情况下提供排序结果,那么它就足够聪明,可以“不做额外的工作”。

进一步实验:向表中添加另一列,但不更改索引。现在您会发现

SELECT * FROM t
的顺序与
SELECT id, name FROM t
不同。我想我已经给了你足够的线索来预测这种差异,如果没有,请询问。

© www.soinside.com 2019 - 2024. All rights reserved.