使用随机值作为主键时的 InnoDB 聚簇索引性能

InnoDB clustered index performance when using random values as primary key

默认情况下,我的InnoDB 存储引擎的主键是自增整数。为了隐藏数据库中的行数,应用程序代码为主键实现了一些随机生成器。

这是一个典型方案的例子:

CREATE TABLE `MUSIC_LINK` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `project_id` int(11) unsigned DEFAULT NULL,
   PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=latin1;

我正在看书,刚刚发现,InnoDB 使用按主键排序的聚簇索引。本质上,这意味着数据库文件中的记录是按主键值索引和排序的。这很好,只要下一条记录的主键总是大于插入的最后一条记录(默认情况下会发生这种情况,因为自动递增约束)。

当主键不再自动递增时会发生什么?为了保持文件按主键排序,每次插入小于最大主键的主键时,必须进行大量重写。

我是否误解了聚集索引在 InnoDB 中的工作方式?因为这听起来像是一个巨大的性能问题。

InnoDB:

对于 AUTO_INCREMENT PRIMARY KEY,"next" 行将被放置在保存 table 数据的 BTree 的 "end" 处。这样效率高,"last"块会更新很多

注意:块保存在 buffer_pool 中,最终 写入磁盘。

使用 "random" PK,例如 GUID、UUID、MD5、SHA1 等,要插入的 "next" 行需要进入 BTree 中的某个 'random' 位置保存数据。如果 buffer_pool 足够大,那么必要的块仍将位于其中。所以效率和AI没有太大区别。

另一方面,如果数据太大无法放入 buffer_pool(或其他 activity 不断将块挤出),则插入需要先获取块修改它。

例如,如果 table 是 buffer_pool 中可以容纳的大小的 20 倍,那么下一次随机写入将有 20 个块中的 1 个是缓存。也就是说,95% 的时间 INSERT 必须等待磁盘读取。

但是...您引发了对 INSERTs 的讨论。 SELECTs 呢?选择有什么模式(如果有的话)?如果反正是'random',那么PK的类型无所谓。另一方面,如果选择倾向于获取 "recent" 项(例如,新闻文章),那么 AI 会赢得较大的 tables,因为所需块被缓存的可能性增加。

集群

评论意味着对 "cluster/ed/ing" 的一些混淆。一些定义(在 MySQL/MariaDB 上下文中):

  • 一组数据相同的服务器,协同工作。 NDB Cluster vs Galera Cluster vs Clustrix(第 3 方产品)
  • A "clustered index" 是当 data 附加到索引时。在 InnoDB 中,PK 始终与数据聚类。 (注:MyISAM,其他厂商不一定这样做。)
  • 当要获取的记录在磁盘布局中彼此相邻时(认为 PK 二级索引),那么这些行是 "clustered together"。这是值得注意的,因为获取一个块会得到您需要的几行。

所以,回到评论:

  • PRIMARY KEY 中跳来跳去(由于使用了我所谓的随机 PK,或者只是因为没有按相关顺序获取行)在 table 中跳来跳去。
  • 一个 UUID 有一个 "sorted order",但它对很多东西都没有用。