qdi*_*nar 8 mysql index database-internals
在 MySQL、MyISAM 和 InnoDB 中,不是索引的列是否与索引一起在磁盘上排序?
我开始写的一个错误想法:
我认为可能不是,因为它们没有被编入索引;如果它们被排序,那将意味着它们是索引。
这是不正确的,因为每个索引列都是按其自己的内容顺序排序的,但我问的是每行(或仅某些列)及其相应索引的排序。
为了解释一下,我说:这对于通过索引更快地选择并排的行范围很有用。例如,如果我想select * where id >1000 and id<2000(可能是 MySQL 语法有错误,我不太了解),那么 id 列本身可以从磁盘中快速读取,因为它的单元格从 1000 到 2000 可能在物理磁盘上保持在一起. 但是id 1000到2000对应的其他列内容可能会写在物理磁盘的不同位置。如果它们也被排序,它们将被更快地读取。我想,也许 MySQL 会自动对物理磁盘上的列进行排序,以实现此类操作的性能。
它们是否在其他类型的数据库(PostgreSQL 等)中排序?
12 月 27 日:我从 2 个答案中看到,在存在聚集索引/主键的情况下,简单行本身不会在物理磁盘上排序(正如我认为的那样),甚至聚集索引也是未排序,如果它是 b 树,我已经阅读了有关 b 树的内容,并看到它的节点,据我所知,位于磁盘上的随机位置。
在某些情况下,它们可能会被排序。该分类指数通常被称为聚集键。如果是这种情况,则整个表都存储在此类索引中(通常以某种 B 树结构)。
在另一种情况下,表结构被称为堆,行在它们来时存储,删除数据块中的“空洞”,这些空洞后来被新行填充,因此甚至不保留“插入顺序”。
MyISAM 使用堆结构,每一行都由数据文件中的偏移量(数组索引的排序)标识。然后,每个索引都包含每行的索引列,按正确顺序排序并使用偏移编号来定位实际行。这意味着通过任何索引访问行意味着在索引(B 树)中定位正确的节点,然后从数据文件中读取正确的偏移量(可能会随机寻找磁盘的不同部分) )。
InnoDB 使用主键聚类(或者如果没有定义,则使用第一个非空唯一键,或者添加一个内部自动递增列 - 因此行总是以某种方式排序)。在这种情况下,主键的访问是“直接”的,当找到正确的值时,您手头就有整行,无需进行第二次读取。另一方面,二级索引不能像 MyISAM 那样存储偏移量(因为 B 树正在动态地重新平衡自身,因此特定行的偏移量可以随时更改)并且它们存储该行的主键值 - 所以通过辅助键访问意味着在 InnoDB 中进行两次 B 树搜索。
MS SQL Server 提供了使主键(或另一个索引)成为聚集或非聚集的选项,因此您可以在堆(没有聚集索引)和树结构(聚集一个索引)之间进行选择。所有其他非聚集索引在堆情况下存储特殊 (RowID) 值,在 CI 情况下存储行的聚集键值。
PostgreSQL 仅使用堆表,但允许您根据需要按某个索引对它们重新排序(您必须触发它,因此在操作之后对行进行排序,但进一步写入表可能会再次破坏该顺序)。
TokuDB(第 3 方 MySQL/MariaDB 引擎)可以在一个表上使用多个集群键 - 它有效地维护了表的多个副本,每个副本以不同的方式排序。它带有写入的惩罚,但 TokuDB 声称使用了一些他们称之为分形索引的想法,这应该使惩罚变得非常小。
如果您需要对某些查询使用该功能,您可以通过创建一个覆盖索引来“模拟”它- 这样您的查询需要的列可以随时以正确的顺序使用,但这同样意味着维护(部分的) 索引中的表。
一般而言,对数据库的简短回答是:不,表中行的物理顺序通常与该表上的某些索引不同。
一般来说(我之所以这么说是因为在某些特殊情况下这是不正确的)表和索引是磁盘上的两种不同的物理结构。传统的 RDBM 存储数据,以便来自一个表行(而不是列)的值在磁盘上彼此相邻;行本身不以任何特定顺序存储。另一方面,索引条目是按顺序存储的;典型的 b 树索引包含索引列的排序值(但不是其他列!)和某种指向表中整行位置的指针,正如我之前所说,它是磁盘上的一个单独的物理结构。
话虽如此,但也有特殊情况。例如,MySQL 的 InnoDB 以类似索引的结构存储实际数据行。将行放置在此类“索引表”中的索引通常是表的主键;这样的索引称为聚集索引。但是当然,InnoDB 表可能有其他索引,并且这些索引中的行顺序(即包含在相应索引中的行列)与表本身中的行顺序无关。