程序员Android开发

高性能索引优化策略(四):聚集索引和非聚集索引数据结构及优劣对比

2021-01-30  本文已影响0人  岛上码农

聚集索引并不是一个单独的索引类型,实际上是一种数据存储的方式。聚集索引的实现细节各有不同,在InnoDB引擎中,聚集索引实际上是将索引和数据行使用同样的结构存储在一个二叉树中。

如果数据表中有聚集索引,则数据行实际上是存在所以的叶子节点。“聚集”的形式实际是指相邻键值的数据行是邻近存储的。因为一行数据不能存储在两个叶子节点上,因此在数据表中只能有一个聚集索引。由于是存储引擎负责索引的实现,因此并不是全部的存储引擎都支持聚集索引。在这里我们只讨论InnoDB,但支持聚集索引的存储引擎实现聚集索引的原理都大同小异。

下图展示了数据记录在聚集索引的存储布局。注意,叶子节点包含了完整的数据行,而其他节点仅仅只有索引。在这个图中,索引列使用的是整数。


聚集索引数据存储

有些数据库服务器允许我们选择对哪个索引进行聚集,但MySQL的任意内置的存储引擎都不支持这么做。InnoDB使用主键对数据进行聚集,这意味着上图的索引列实际上是主键列。

如果数据表没有定义主键,InnoDB会选择使用唯一的非空列(Not Null)索引替代。如果没有这样的索引,InnoDB会定义一个隐藏的主键去完成数据聚集(因此,数据表最好自己定义主键)。InnoDB的只能在一个数据页中进行数据聚集,因此即便是临近的索引值的数据存储页也可能间隔很远。

一个聚集主键能够提高性能,但同样也可能导致严重的性能问题。因此,你应当谨慎考虑聚集的使用,尤其是当你将一个数据表的存储引擎从InnoDB改为其他引擎时。

聚集索引具有如下的优势:

如果你在设计数据表和查询时充分利用这些好处,将能显著提升性能。然而,聚集索引也有缺点:

InnoDB和MyISAM数据布局比较

聚集和非聚集数据布局,以及主键和非聚集索引的差别可能让人困惑和奇怪。我们可以比较一下InnoDB和MyISAM对下面数据表的存储布局来深入了解一下。

CREATE TABLE layout_test (
  col1 int NOT NULL,
  col2 int NOT NULL,
  PRIMARY KEY(col1),
  KEY(col2)
);

假设这个表产生了主键1到10000的数据,采用的是随机顺序插入的,然后在通过OPTIMIZE TABLE进行了优化。换言之,数据在磁盘上是有序排列的,但行可能是随机顺序的。数据列col2使用1-100的随机值填充,因此存在很多的重复值。

MyISAM的数据布局更简单些,MyISAM按照插入的顺序在磁盘存储数据,如下图所示。我们以0开始展示了数据行编号,由于每一行的大小是固定的,MyISAM可以从表最开始的地方根据所需要的字节数来找到任意行(MyISAM内部并不总是使用行号,而是根据行是否固定大小或可变大小使用不同的策略)。


数据次序

这种结构使其很容易构建索引,下图绘制了一个数据系列,这个图中,物理的细节(例如存储页)被抽象隐藏,在索引中只有节点。每个索引的叶子节点可以简单地包含对应的行号,在下图是其主键。在这里隐藏了一些细节,例如在前一个节点后有少个内部的二叉树节点,但这对于理解非聚集存储引擎基础的数据布局来说并不重要。


MyISAM聚集索引结构

那对于col2列的索引怎么样。实际上,它和其他索引一样。


MyISAM非聚集索引结构MyISAM非聚集索引结构

事实上,在MyISAM中,主键和其他索引并没有结构上的区别。主键只是一个简单的唯一、不为空的索引,仅仅是名字命名为主键而已。

InnoDB由于聚集索引的组织方式,存储同样数据的结构十分不同,如下图所示。


InnDB聚集索引结构InnDB聚集索引结构

初看这张图,感觉似乎和MyISAM的并无太大不同,但是仔细再看一遍,实际上这个图展示了整张数据表,而不只是索引。由于聚集索引在InnoDB中已经是整张表了,因此这里没有像在MyISAM中的独立的行存储。

InnoDB的聚集索引每个叶子节点都包含主键值、事务ID、回滚指针以便进行事务和MVCC(Multi Version Cocurrent Control, 并发多版本控制),以及剩下的其他列(示例数据表就是col2)。如果主键作用在一个列的前缀上,InnoDB会在其他列中包含主键列的完整值。

同样,与MyISAM相比,非聚集索引和聚集索引有很大不同。相比于存储行指针,InnoDB非聚集索引的叶子节点存储的是主键值,由主键再指向数据。这个策略在行移动或数据分页需要维护非聚集索引时,减少了很多工作。使用行主键值作为指针意味着索引更大,但也意味着InnoDB可以移动行而不需要去更新非聚集索引的指针。下图展示了非聚集索引的数据布局,可以看到非聚集索引实际上存储了主键的值。


InnoDB非聚集索引结构InnoDB非聚集索引结构

这些图展示了二叉树的叶子节点,但是我们隐藏了非叶子节点的细节。InnoDB中非叶子节点的二叉树的每一个节点都包含索引列,并另外附加了下一个层级的节点的指针(有可能是非叶子节点也可能是叶子节点)。这个对聚集索引和非聚集索引都一样。下图展示了InnoDB和MyISAM的索引的抽象结构对比,从中可以看出二者的不同之处。


InnoDB和MyISAM存储结构对比InnoDB和MyISAM存储结构对比
上一篇下一篇

猜你喜欢

热点阅读