作者
digoal
日期
2019-07-02
标签
PostgreSQL , 阿里云
背景
《PostgreSQL 优化CASE - 无序UUID性能问题诊断》
业务系统中,对于需要全球唯一的主键,或者需要全局唯一的主键时,使用数据库自身的序列可能无法满足全球或全局需求。通常会使用UUID库,产生UUID。
然而UUID通常是无序的,如果UUID需要创建主键或索引,用于高效率检索时,无序的数据,大量的写入是对于BTREE索引会带来较大的分裂问题,因为下一次写入的数据和上一次写入的数据永远(或者绝大多数时候)不在同一个INDEX BLOCK,从而IO问题会非常明显,另外就是索引的分裂问题也会很明显。
UUID有序化是一个解法:
《PostgreSQL 优化CASE - 有序UUID插件》
《PostgreSQL sharding有序UUID最佳实践 - serial global uuid stored in 64bit int8》
《PostgreSQL 优化CASE - 无序UUID性能问题诊断》
除了UUID算法本身有序化,还有一种方法,在UUID前面加PREFIX,让这个PREFIX有序就可以,组合起来后依旧是全球唯一。
例如数据的产生时间,作为PREFIX。(根据写入吞吐决定用多长的PREFIX),写入吞吐越大,PREFIX要约精确(例如到秒级),因为这样才能尽可能使得新写入的记录在与UUID拼接后,与最近写入的记录还能处于同一或尽可能少的的INDEX数据块。
例子
```
postgres=> create extension "uuid-ossp";
postgres=> create table testa(pk text primary key, info text, crt_time timestamp);
CREATE TABLE
postgres=> insert into testa values (extract(epoch from now()::timestamp(0))::text||uuid_generate_v4(), 'test', now());
INSERT 0 1
postgres=> insert into testa values (extract(epoch from now()::timestamp(0))::text||uuid_generate_v4(), 'test', now());
INSERT 0 1
postgres=> select * from testa;
pk | info | crt_time
------------------------------------------------+------+----------------------------
15620796179e36c7d3-aad2-429e-9560-9029e50002ff | test | 2019-07-02 15:00:17.091443
156207961925395f4d-4406-42b3-b3b2-fb4735f25c4c | test | 2019-07-02 15:00:18.675147
(2 rows)
postgres=> select extract(epoch from now()::timestamp(0));
date_part
1562079750
(1 row)
postgres=> select extract(epoch from now()::timestamp(0));
date_part
1562079751
(1 row)
```
加了前缀后,数据变得有序,虽然整个长度会增加,但是在索引里面是有序的。
当然如果可以直接使用有序UUID是更好的。
参考
《PostgreSQL 优化CASE - 有序UUID插件》
《PostgreSQL sharding有序UUID最佳实践 - serial global uuid stored in 64bit int8》
《PostgreSQL 优化CASE - 无序UUID性能问题诊断》
PostgreSQL 许愿链接
您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.
9.9元购买3个月阿里云RDS PostgreSQL实例
PostgreSQL 解决方案集合
德哥 / digoal's github - 公益是一辈子的事.





