PostgreSQL 优化CASE - 有序UUID插件

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核4GB
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
云原生数据库 PolarDB 分布式版,标准版 2核8GB
简介: 标签PostgreSQL , uuid , 无序uuid , 索引分裂 , io , 性能诊断背景无序UUID会带来很多问题,例如索引分裂膨胀,离散IO,WAL膨胀等,详见以前的分析。Regular random UUIDs are distributed uniformly over the whole range of possible values.

标签

PostgreSQL , uuid , 无序uuid , 索引分裂 , io , 性能诊断


背景

无序UUID会带来很多问题,例如索引分裂膨胀,离散IO,WAL膨胀等,详见以前的分析。

Regular random UUIDs are distributed uniformly over the whole range of possible values.

This results in poor locality when inserting data into indexes -

all index leaf pages are equally likely to be hit, forcing the whole index into memory.

With small indexes that's fine, but once the index size exceeds shared buffers (or RAM), the cache hit ratio quickly deteriorates.

《PostgreSQL 优化CASE - 无序UUID性能问题诊断》

《PostgreSQL sharding有序UUID最佳实践 - serial global uuid stored in 64bit int8》

https://blog.2ndquadrant.com/sequential-uuid-generators/

如何生成有序UUID呢?

以下是Instagram的做法

《PostgreSQL sharding有序UUID最佳实践 - serial global uuid stored in 64bit int8》

除此之外,还可以使用sequential-uuids这个插件:

https://github.com/tvondra/sequential-uuids

sequential-uuids插件例子

UUID为16字节类型,生成算法:在16字节的可枚举空间里随机生成,因此可以认为整个索引的所有页面都是热的,因为新生成的UUID值可能写入索引的任意位置。当UUID列的索引超出内存大小时,持续写入会不可避免的会引入较多的磁盘操作(FULL PAGE WRITE(由于可能写任意PAGE))。

而传统的序列方式的UUID,实际上是往一个方向递增会递减的。主要的问题:

1、对撞,由于取值范围降到了8字节(BIGINT的序列,或者时间戳(取决于精度))。所以对撞空间比UUID(16字节)小了,容易出现重复。

2、BTREE里面,往一个方向递增,如果一次性大量删除历史数据,会导致那些索引页全部废弃,导致膨胀。(当然,如果后续还有数据持续写入,那些完全删除了数据的索引页还可以被重复利用。)

为了解决这2个问题,提出了GUID的概念

https://en.wikipedia.org/wiki/Universally_unique_identifier

http://www.informit.com/articles/article.aspx?p=25862

GUID,实际上就是把数据拆成两部分,一部分自增,一部分随机。同样整个类型使用的是16字节。例如prefix部分使用自增(在有限空间内WRAP,重复使用),另一部分使用随机。同时解决了以上两个问题。

sequential-uuids插件就是这个思路实现的,

(block ID; random data)  

提供了两种prefix算法:

1、prefix为自增序列,如果block ID使用2字节存储,一个索引BLOCK里面可以存储256条记录(假设8K的BLOCK,一条记录包括uuid VALUE(16字节)以及ctid(6字节),所以一个索引页约存储363条记录(8000/(16+6)))

uuid_sequence_nextval(sequence regclass, block_size int default 65536, block_count int default 65536)  
/*  
 * uuid_sequence_nextval  
 *	generate sequential UUID using a sequence  
 *  
 * The sequence-based sequential UUID generator define the group size  
 * and group count based on number of UUIDs generated.  
 *  
 * The block_size (65546 by default) determines the number of UUIDs with  
 * the same prefix, and block_count (65536 by default) determines the  
 * number of blocks before wrapping around to 0. This means that with  
 * the default values, the generator wraps around every ~2B UUIDs.  
 *  
 * You may increase (or rather decrease) the parameters if needed, e.g,  
 * by lowering the block size to 256, in wich case the cycle interval  
 * is only 16M values.  
 */  

如下,假设block_size设置为256,则表示每256个连续值的prefix是一样的。

(nextval('seq') / 256) % 65536  

意思是每256条记录,从0开始,prefix递增1,到65535后循环。

seq=1, prefix=0  
  
seq=2, prefix=0  
  
seq=256, prefix=1  
  
...  

2、prefix为时间戳。

uuid_time_nextval(interval_length int default 60, interval_count int default 65536) RETURNS uuid  
/*  
 * uuid_time_nextval  
 *	generate sequential UUID using current time  
 *  
 * The timestamp-based sequential UUID generator define the group size  
 * and group count based on data extracted from current timestamp.  
 *  
 * The interval_length (60 seconds by default) is defined as number of  
 * seconds where UUIDs share the same prefix). The prefix length is  
 * determined by the number of intervals (65536 by default, i.e. 2B).  
 * With these parameters the generator wraps around every ~45 days.  
 */  

默认每60秒内的数据prefix是一样的,prefix递增1,到65535后循环。

(timestamp / 60) % 65536  

65535为prefix使用掉的字节数的取值空间,例如2字节,则为65536。

使用举例:

git clone https://github.com/tvondra/sequential-uuids  
cd sequential-uuids/  
USE_PGXS=1 make  
USE_PGXS=1 make install  
postgres=# create sequence seq;  
CREATE SEQUENCE  
postgres=# select uuid_sequence_nextval('seq'::regclass);  
        uuid_sequence_nextval           
--------------------------------------  
 0000c98b-24e3-648d-d974-31a2a23e3f49  
(1 row)  
postgres=# select uuid_sequence_nextval('seq'::regclass,256);  
        uuid_sequence_nextval           
--------------------------------------  
 0000a807-5878-05c1-7379-262e74e2d83e  
(1 row)  
  
postgres=# select uuid_sequence_nextval('seq'::regclass,256);  
        uuid_sequence_nextval           
--------------------------------------  
 00005da3-473e-61d7-d2aa-ef3c0ad5ad3d  
(1 row)  
  
postgres=# select uuid_time_nextval();  
          uuid_time_nextval             
--------------------------------------  
 97a52b75-fbc0-8758-eecf-be213e66f388  
(1 row)  
  
postgres=# select uuid_time_nextval(300);  
          uuid_time_nextval             
--------------------------------------  
 84bab38b-87d5-17cd-07d3-93bd0c30d919  
(1 row)  
  
postgres=# select uuid_time_nextval(300);  
          uuid_time_nextval             
--------------------------------------  
 84bacffe-69fb-7464-bbfb-bca9ca7bcb08  
(1 row)  

参考

https://github.com/tvondra/sequential-uuids

《PostgreSQL 优化CASE - 无序UUID性能问题诊断》

《PostgreSQL sharding有序UUID最佳实践 - serial global uuid stored in 64bit int8》

https://blog.2ndquadrant.com/sequential-uuid-generators/

https://github.com/tvondra/sequential-uuids/blob/master/sequential_uuids.c

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
19天前
|
关系型数据库 MySQL Linux
MySQL原理简介—6.简单的生产优化案例
本文介绍了数据库和存储系统的几个主题: 1. **MySQL日志的顺序写和数据文件的随机读指标**:解释了磁盘随机读和顺序写的原理及对数据库性能的影响。 2. **Linux存储系统软件层原理及IO调度优化原理**:解析了Linux存储系统的分层架构,包括VFS、Page Cache、IO调度等,并推荐使用deadline算法优化IO调度。 3. **数据库服务器使用的RAID存储架构**:介绍了RAID技术的基本概念及其如何通过多磁盘阵列提高存储容量和数据冗余性。 4. **数据库Too many connections故障定位**:分析了MySQL连接数限制问题的原因及解决方法。
|
22天前
|
SQL 关系型数据库 MySQL
MySQL进阶突击系列(07) 她气鼓鼓递来一条SQL | 怎么看执行计划、SQL怎么优化?
在日常研发工作当中,系统性能优化,从大的方面来看主要涉及基础平台优化、业务系统性能优化、数据库优化。面对数据库优化,除了DBA在集群性能、服务器调优需要投入精力,我们研发需要负责业务SQL执行优化。当业务数据量达到一定规模后,SQL执行效率可能就会出现瓶颈,影响系统业务响应。掌握如何判断SQL执行慢、以及如何分析SQL执行计划、优化SQL的技能,在工作中解决SQL性能问题显得非常关键。
|
2月前
|
SQL 关系型数据库 MySQL
深入解析MySQL的EXPLAIN:指标详解与索引优化
MySQL 中的 `EXPLAIN` 语句用于分析和优化 SQL 查询,帮助你了解查询优化器的执行计划。本文详细介绍了 `EXPLAIN` 输出的各项指标,如 `id`、`select_type`、`table`、`type`、`key` 等,并提供了如何利用这些指标优化索引结构和 SQL 语句的具体方法。通过实战案例,展示了如何通过创建合适索引和调整查询语句来提升查询性能。
419 9
|
14天前
|
缓存 算法 关系型数据库
MySQL底层概述—8.JOIN排序索引优化
本文主要介绍了MySQL中几种关键的优化技术和概念,包括Join算法原理、IN和EXISTS函数的使用场景、索引排序与额外排序(Using filesort)的区别及优化方法、以及单表和多表查询的索引优化策略。
MySQL底层概述—8.JOIN排序索引优化
|
15天前
|
SQL 关系型数据库 MySQL
MySQL底层概述—7.优化原则及慢查询
本文主要介绍了:Explain概述、Explain详解、索引优化数据准备、索引优化原则详解、慢查询设置与测试、慢查询SQL优化思路
MySQL底层概述—7.优化原则及慢查询
|
15天前
|
存储 缓存 关系型数据库
MySQL底层概述—5.InnoDB参数优化
本文介绍了MySQL数据库中与内存、日志和IO线程相关的参数优化,旨在提升数据库性能。主要内容包括: 1. 内存相关参数优化:缓冲池内存大小配置、配置多个Buffer Pool实例、Chunk大小配置、InnoDB缓存性能评估、Page管理相关参数、Change Buffer相关参数优化。 2. 日志相关参数优化:日志缓冲区配置、日志文件参数优化。 3. IO线程相关参数优化: 查询缓存参数、脏页刷盘参数、LRU链表参数、脏页刷盘相关参数。
MySQL底层概述—5.InnoDB参数优化
|
6天前
|
监控 关系型数据库 MySQL
MySQL和SQLSugar百万条数据查询分页优化
在面对百万条数据的查询时,优化MySQL和SQLSugar的分页性能是非常重要的。通过合理使用索引、调整查询语句、使用缓存以及采用高效的分页策略,可以显著提高查询效率。本文介绍的技巧和方法,可以为开发人员在数据处理和查询优化中提供有效的指导,提升系统的性能和用户体验。掌握这些技巧后,您可以在处理海量数据时更加游刃有余。
36 9
|
17天前
|
关系型数据库 MySQL 数据库
从MySQL优化到脑力健康:技术人与效率的双重提升
聊到效率这个事,大家应该都挺有感触的吧。 不管是技术优化还是个人状态调整,怎么能更快、更省力地完成事情,都是我们每天要琢磨的事。
61 23
|
5天前
|
关系型数据库 MySQL
图解MySQL【日志】——磁盘 I/O 次数过高时优化的办法
当 MySQL 磁盘 I/O 次数过高时,可通过调整参数优化。控制刷盘时机以降低频率:组提交参数 `binlog_group_commit_sync_delay` 和 `binlog_group_commit_sync_no_delay_count` 调整等待时间和事务数量;`sync_binlog=N` 设置 write 和 fsync 频率,`innodb_flush_log_at_trx_commit=2` 使提交时只写入 Redo Log 文件,由 OS 择机持久化,但两者在 OS 崩溃时有丢失数据风险。
17 3
|
17天前
|
SQL 关系型数据库 MySQL
MySQL原理简介—11.优化案例介绍
本文介绍了四个SQL性能优化案例,涵盖不同场景下的问题分析与解决方案: 1. 禁止或改写SQL避免自动半连接优化。 2. 指定索引避免按聚簇索引全表扫描大表。 3. 按聚簇索引扫描小表减少回表次数。 4. 避免产生长事务长时间执行。

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版