内容提要
本文比较了四种不同的主键存储方法:文本字段存储UUID、PostgreSQL的uuid数据类型、uuidv7代码和bigint。测试结果显示,uuidv7性能优于bigint,而uuidv4与bigint性能相当。文章还讨论了缓存压力对性能的影响以及UUID和bigint的大小差异。
延伸解读
测试环境与可复现性
基准测试在AWS EC2 c7a.medium实例上进行,配置为1个AMD EPYC Genoa核心、2GB内存、16k IOPS的gp3卷,运行Ubuntu 22.04和PostgreSQL开发版。作者提供了完整的脚本和步骤,包括应用UUIDv7补丁和调整参数,读者可复现测试。但需注意,测试基于单节点和特定硬件,结果可能因环境而异。
缓存压力与数据局部性
文章指出,uuidv4由于缺乏数据局部性,导致主键索引占用大量缓冲区缓存,增加了工作集大小,从而拖慢整体性能。而uuidv7具有时间有序性,改善了局部性,减少了缓存压力。这解释了为何uuidv7在插入和查询混合负载下表现更优。
UUID与bigint的权衡
尽管uuidv7在性能上接近bigint,但bigint在存储大小上仍有25%的优势。选择UUID意味着接受128位 versus 64位的总大小惩罚,可能影响缓存效率和I/O。对于追求极致性能或存储敏感的场景,bigint仍是更经济的选择。
测试的局限与待验证点
作者承认测试存在不足:并发查询未使用UUID列,可能未充分体现缓存压力差异;且uuidv7与bigint速度相同可能因未触发缓存瓶颈。未来需修复脚本以展示性能差距。此外,测试仅基于单表插入,未涵盖复杂查询模式。
Q&A
在PostgreSQL中,存储UUID主键有哪几种方法?它们的性能差异如何?
文章比较了四种方法:文本字段存储UUID、PostgreSQL的uuid数据类型、uuidv7代码和bigint。测试结果显示,uuidv7性能优于bigint,而uuidv4与bigint性能相当。具体来说,插入一百万行,uuid::text耗时410秒,uuidv4耗时375秒,uuidv7耗时290秒,bigint耗时290秒。
为什么不应该将UUID存储在文本字段中?
因为将UUID存储在文本字段中会导致性能下降和存储空间增大。测试中,uuid::text插入一百万行耗时410秒,最终大小为4.31 GB,而uuidv4仅需375秒,大小为2.65 GB,比文本字段快10%且小63%。
uuidv7相比uuidv4有哪些优势?
uuidv7在性能和存储大小上都优于uuidv4。测试中,uuidv7插入一百万行耗时290秒,平均速率3420 tps,最终大小2.47 GB;而uuidv4耗时375秒,平均速率2670 tps,最终大小2.65 GB。uuidv7比uuidv4快30%且小7%。
bigint作为主键相比UUID有什么优势?
bigint作为主键在存储大小上比UUID更有优势。测试中,bigint插入一百万行最终大小为1.97 GB,比uuidv7小25%。虽然速度与uuidv7相同(290秒),但bigint是64位,而UUID是128位,因此选择UUID会有总大小的惩罚。
缓存压力如何影响UUID主键的性能?
uuidv4由于缺乏数据局部性,导致主键索引消耗大量缓存空间,从而减少其他索引和表的可用缓存,显著降低整体工作负载性能。而uuidv7具有更好的数据局部性,因此缓存压力较小,性能更优。
如何复现这个UUID基准测试?
作者提供了完整的基准测试脚本和设置说明。需要按照Copy-and-Paste Postgres Dev Env的步骤,使用c7a.medium实例和gp3卷,切换到PostgreSQL的特定提交并应用UUIDv7补丁,设置shared_buffers=1G和max_wal_size=204800,然后运行提供的pgbench脚本。