求教:OceanBase 主键 的性能瓶颈问题 与 最佳实践

大家好,我之前在调研数据库选型时,曾看到阿里云 【PolarDB-X】的官方号在 知乎 发过一篇关于数据库性能评测的回答

image

如图所示,其中有这样一段,说 OceanBase 在使用 默认的 AUTO_INCREMENT 作为自增ID 的情况下,会存在性能瓶颈 。

该回答撰写于快2年前了。
我想了解一下,这个性能瓶颈在当前最新版本 4.2.2 社区版 是否有所改善呢 ?

或者,大家对于 OceanBase 自增长ID 的使用,有没有最佳实践可以分享 ?

可以分不同情况讨论一下,比如:

  1. 要求连续自增ID(类似 MySQL 即可)
  2. 要求自增ID (不要求连续)
  3. ID只要求唯一(不要求自增,可以随机 )

补充1:可参考 官方文档《定义自增列》

补充2:我看官方文档里面有如下描述:

如果有一个电商SaaS,【订单表】有 商户ID(int) 和 订单号(varchar(32)) 存在唯一约束,这个时候我也要用 这两个字段 做联合主键吗?

先在此谢过 ~

数据结构:使用两个字段作为联合主键可以简化数据结构,因为表中只需要存储这两个字段,而不需要存储其他字段。
数据一致性:如果订单表中的数据需要与其他表的数据进行关联,那么使用两个字段作为联合主键可以保证数据的一致性,因为可以通过联合主键来确定订单的唯一性。
综上所述,您的这个例子建议使用商户ID和订单号字段作为联合主键,以确保订单的唯一性,并简化数据结构

感谢大神 @piping 回复 !

之前 MySQL 采用的是 B+Tree 的结构来存储数据,一般建议 ID是自增的,这样可以避免随机插入,导致 MySQL 频繁裂页,进而导致检索数据时 IO 开销增加。

因为 商户ID + 订单号 也很明显不是自增的,所以我才有此疑问。如果 OceanBase 照样推荐使用它们联合作为主键,是因为 LSM-Tree 能够很好地处理 裂页 问题么 ?

此外,除了主键索引,我们一般还会额外在关键业务表上创建几个二级索引。
在 MySQL 中,因为每个二级索引的叶子节点都会存储相应行的主键值。所以,如果主键较大,那么每个二级索引的叶子节点所需的空间也会更大,因为它们需要存储更大的主键值。

如果主键是 bigint 的自增ID,在二级索引上存储,也就占用 8个字节 的空间。
如果主键是 int + varchar(32) 这种联合索引,是不是就意味着,也要占用至少 4+32 个字节的空间呢?
如果有多个二级索引(3个左右),是不是就要重复多占用不少空间。这样的话,存储空间 以及 维护这些二级索引的开销不是也增大了许多么 ?
还是说,OceanBase 实现机制不一样,有什么改进的措施 ?

在 OceanBase 中,表的主键是唯一索引,唯一索引的叶子节点存储的是主键值的哈希值,而不是主键值本身。因此,主键的大小对二级索引的叶子节点大小没有影响。
例如,如果主键是 int + varchar(32) 的联合索引,那么二级索引的叶子节点大小仍然是 4 个字节(int 类型)或 8 个字节(varchar 类型),而不是 4+32 个字节。
此外,OceanBase 还支持聚集索引和分布式索引,可以进一步提高查询效率和数据存储空间利用率。
聚集索引是指表中的数据按照主键的顺序进行排序,这样可以加快查询效率。在 OceanBase 中,每个表只能有一个聚集索引,主键就是默认的聚集索引。
分布式索引是指表中的数据按照一个或多个列的值进行排序,这样可以提高查询效率和数据存储空间利用率。在 OceanBase 中,每个表可以有多个分布式索引,并且这些索引可以跨节点、跨数据中心进行分布式部署和数据同步。
综上所述,在 OceanBase 中,使用联合主键作为表的主键不会导致二级索引的叶子节点大小增加,也不会影响查询效率和数据存储空间利用率。同时,OceanBase 还支持聚集索引和分布式索引,可以进一步提高查询效率和数据存储空间利用率。

感谢您的回复!

我可以如下这样总结吗 :

  1. OceanBase 的 二级索引 引用的是 主键 的 哈希值,所以不受主键本身大小的影响。
  2. OceanBase 的 主键索引默认就是 聚集索引,很明显,不管是 int + varchar(32),还是 哈希值,都不是单调递增的,仍然存在随机插入。如果官方还是推荐使用它们作为主键的话,是因为 LSM-Tree 在随机插入下并没有类似 B+Tree 的 数据页分裂导致的 IO性能开销问题吗 ?

再次感谢! :handshake: