主要观点:
- 独特的 ID 生成对应用很关键,用于表示表中的唯一行,常作为主键用于搜索。
- 不建议用
Math.random() + epoch
或随机字符串作为主键,因其在性能等方面存在诸多问题,如比较慢、索引大、易碎片化、参考局部性差等。 - 数值型、顺序 ID 更好,如采用类似雪花算法的方式,具有比较快、索引小、减少碎片化、提高局部性等优势。
- 介绍了数据库内部使用的 B-Trees 结构及相关操作,以及
generateInternalId(int shardId)
方法生成 64 位唯一 ID 的原理,包括时间戳、分片 ID、序列数的组合及位运算过程等,并给出了 Java 实现代码及重要考虑事项(未处理序列溢出、时钟漂移等情况)。
关键信息:
- ID 结构为 64 位,包含 41 位时间戳、10 位分片 ID、12 位序列数及额外 1 位。
- 时间戳基于
2023-01-01 00:00:00 UTC
的System.currentTimeMillis()
计算,约 69.7 年循环。 - 10 位分片 ID 可区分 1024 个数据库分片或应用实例。
- 12 位序列数在同一毫秒同一分片内递增,最多 4096 个。
- 代码通过位运算组合各部分生成 ID,
generateInternalId
方法使用synchronized
保证线程安全。 - 重要考虑事项包括处理序列溢出、时钟漂移及分片 ID 分配等。
重要细节:
- 数据库索引使用 B-Trees 或变体,搜索、插入等操作时间复杂度为 O(log n),字符串比较比整数慢,随机字符串导致索引碎片化和较差的参考局部性。
- 顺序 ID 插入在 B-tree 索引的最右叶节点,减少碎片化和提高写入性能。
generateInternalId
方法中的epoch
为自定义起始时间戳,sequence
使用AtomicInteger
保证原子性递增并通过& 0xFFF
限制在 12 位范围内。- 示例展示了根据当前时间、分片 ID 和序列数生成具体 ID 的过程。
- 提到在个人项目Url Shortener中使用了该方法。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。