大分区表高并发性能提升100倍?阿里云 RDS PostgreSQL 12 特性解读

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 Tair(兼容Redis),内存型 2GB
简介: 世界上几乎最强大的开源数据库系统 PostgreSQL,于 2019 年 10 月 3 日发布了 12 版本,该版本已经在阿里云正式发布。PostgreSQL 12 在功能和性能上都有很大提升,如大分区表高并发性能提升百倍,B-tree 索引空间和性能优化,实现 SQL 2016 标准的 JSON 特性,支持多列 MCV(Most-Common-Value)统计,内联 CTE(Common table expressions)以及可插拔的表存储访问接口等。本文对部分特性进行解读。

作者:凌策
世界上几乎最强大的开源数据库系统 PostgreSQL,于 2019 年 10 月 3 日发布了 12 版本,该版本已经在阿里云正式发布。PostgreSQL 12 在功能和性能上都有很大提升,如大分区表高并发性能提升百倍,B-tree 索引空间和性能优化,实现 SQL 2016 标准的 JSON 特性,支持多列 MCV(Most-Common-Value)统计,内联 CTE(Common table expressions)以及可插拔的表存储访问接口等。本文对部分特性进行解读。

分区表性能

PostgreSQL 对分区表的支持由来已久。在 10.0 之前,分区表需要用户通过继承的方式手动创建,从 10.0 开始支持声明式分区,即通过 SQL 直接创建分区表,改善了分区表的易用性;在 11 中,支持 HASH 分区,并在计划和执行阶段,增强分区裁剪策略,提升分区表查询性能;PostgreSQL 12 进一步增强了分区表的查询和数据导入性能,尤其对分区数量多的场景,查询优化效果尤为显著。

在阿里云创建两个同等规格(4c8g)的 RDS PostgreSQL 11 和 12 的实例,测试不同分区数情况下,使用 COPY 导入 1 亿行数据的性能对比如下。可见,随着分区数增多,导入性能始终优于 PostgreSQL 11。COPY 导入数据的性能提升得益于在 12 中支持了分区表批量插入,在次之前,仅支持一次一行的插入模式。
27.png

对于查询操作,在 PostgreSQL 10 中,会依次检查每个分区表,判断其可能有满足条件的数据,每个分区表的处理与普通表的处理流程类似;PostgreSQL 11 引入了分区裁剪特性,可以更早地定位需要访问的分区;PostgreSQL 12 则近一步将分区裁剪功能前置,避免为每个分区加载元数据并生成相应的内部结构,使得查询计划耗时进一步与无关的分区解耦。由此可见,该优化与查询条件的分区过滤性相关,分区过滤性越好,所需处理的分区越少,优化效果越好。

不同分区数下,分区键(同时也是主键)上的查询性能对比如下。可见,分区数越多,PostgreSQL 12 的性能提升越明显,最高提升达 150 倍。而随着分区数增加,PostgreSQL 12 的性能则保持相对稳定。
28.png

虽然分区表性能有大幅提升,但与单表相比,在很多场景下性能还有一定差距,在做表结构设计时,仍然需要结合实际业务场景,选择是否分区以及分区数量。

索引增强

B-tree 索引被广泛应用于数据库系统中,可以有效减少查询需要访问的数据量,提升查询性能。索引是一种 "空间换时间" 的查询优化策略,本身也会占用一些存储空间,其性能对查询也至关重要。PostgreSQL 12 提升了标准 B-tree 的整体性能,减少了磁盘空间占用,对于复合索引,其空间使用率最多可减少 40%,可以有效节省用户的磁盘空间;对于有重复项的 B-tree 索引,其性能也有所提升。另外,引入 REINDEX CONCURRENTLY 命令,用户可以在业务无感知的情况下重建索引。

我们通过测试直观感受一下 B-tree 索引的空间占用优化。分别在 PostgreSQL 11 和 12 中创建如下表和索引,并插入 2000 万行数据,VACUUM 更新统计信息。

CREATE TABLE foo (
    aid bigint NOT NULL,
    bid bigint NOT NULL
);
ALTER TABLE foo
    ADD CONSTRAINT foo_pkey PRIMARY KEY (aid, bid);
CREATE INDEX foo_bid_idx ON foo(bid);
INSERT INTO foo (aid, bid)
    SELECT i, i / 10000
    FROM generate_series(1, 20000000) AS i; 
VACUUM (ANALYZE) foo;  

分别查看两个 PostgreSQL 版本中 foo_bid_idx 索引的大小,如下:

  #  PostgreSQL 11
postgres=> \di+ foo_bid_idx
                                    List of relations
 Schema |    Name     | Type  |    Owner    | Table | Persistence |  Size  | Description
--------+-------------+-------+-------------+-------+-------------+--------+-------------
 public | foo_bid_idx | index |   postgres  | foo   | permanent   | 544 MB |
(1 row)
2 .# PostgreSQL 12
postgres=> \di+ foo_bid_idx
                                    List of relations
 Schema |    Name     | Type  |    Owner    | Table | Persistence |  Size  | Description
--------+-------------+-------+-------------+-------+-------------+--------+-------------
 public | foo_bid_idx | index |   postgres  | foo   | permanent   | 408 MB |
(1 row)  

可见,PostgreSQL 11 的索引比 PostgreSQL 12 大 33%,在索引较多的场景下,如此大幅度的空间节省还是很可观的。

除 B-tree 索引外,其他索引也有增强。如减小生成 GiST、GIN 和 SP-GiST 索引的WAL日志的开销,支持用 GiST 创建覆盖索引,支持用 SP-GiST 索引的 distance 运算符执行 K-NN 查询等。

支持 SQL/JSON 路径语言(path language)

PostgreSQL 在之前的版本中就已经支持了 JSON 数据类型,并支持对简单 JSON 数据的查询操作,如果 JSON 数据比较复杂,如嵌套较多,包含数组等,则不能便捷地查询其中的值,往往需要依赖外部插件来实现,比如支持 SQL/JSON 路径语言 的 jsquery 插件。

PostgreSQL 12 对非结构化数据的支持再进一步。内置支持了 SQL 2016 标准引入的 JSON 特性和丰富的路径查询方法,引入新的数据类型 jsonpath 表示路径表达式(path expression),支持 JSON 上的各种复杂查询,不再依赖插件。具体的使用方法可以参考文档,在此不赘述。

参数控制 Prepared 计划

对于重复执行的 PREPARE 语句,PostgreSQL 会缓存其执行计划,执行 PREPARE 语句时,PostgreSQL 会自动选择是重新生成一个新的计划(通常称之为定制计划,custom plan),还是使用缓存的计划(即通用计划,generic plan),但在特定场景下,数据库的选择可能并不是最优的。PostgreSQL 12 为用户提供了一个参数 plan_cache_mode 来自主选择使用哪种计划,比如查询的参数如果总是固定的常量,则可以显式设置该参数,使优化器总是使用通用计划,避免 SQL 解析和重写的代价,从而优化查询性能。

执行** PREPARE **并运行,前 5 次均使用定制计划:
postgres=> prepare p(integer) as select aid from foo where aid=$1;
PREPARE
postgres=> EXPLAIN EXECUTE p(1);
                               QUERY PLAN------------------------------------------------------------------------
 Index Only Scan using foo_pkey on foo  (cost=0.44..1.56 rows=1 width=8)
   Index Cond: (aid = 1)
(2 rows)
1.# 后续四次执行的结果在此省略  

执行第 6 次时使用通用计划,如下:
> postgres=> EXPLAIN EXECUTE p(1);
                               QUERY PLAN
-------------------------------------------------------------------------
 Index Only Scan using foo_pkey on foo  (cost=0.44..1.56 rows=1 width=8)
   Index Cond: (aid = $1)
(2 rows)  

重新执行 > PREPARE  
,并设置 > plan_cache_mode  
 为 > force_generic_plan  
,观察计划使用情况,可见第 1 次执行时就会使用通用计划,而无需等到第 6 次执行。
> postgres=> DEALLOCATE p;
DEALLOCATE
postgres=> prepare p(integer) as select aid from foo where aid=$1;
PREPARE
(1) # plan_cache_mode 设置为 force_generic_plan
postgres=> set plan_cache_mode = force_generic_plan;
SET
postgres=> EXPLAIN EXECUTE p(1);
                               QUERY PLAN
-------------------------------------------------------------------------
 Index Only Scan using foo_pkey on foo  (cost=0.44..1.56 rows=1 width=8)
   Index Cond: (aid = $1)
(2 rows)  

是否使用通用计划可以通过执行计划中变量是否做了参数化处理来判断。

可插拔表存储接口

一直以来,PosgreSQL 都只支持 heap 表这一种存储引擎,其实现与其他模块耦合较多。PostgreSQL 12 借鉴自身索引可扩展的实现方式,抽象出一层存储引擎访问接口,为后续支持多种存储引擎奠定了基础,如 ZHeap、列存、K/V 存储、内存引擎等。

可插拔表存储访问接口的架构如下,在原有架构基础上,增加了 表访问管理层(Table Access Manager),提供统一的表访问接口,不同的存储引擎只需实现该接口即可接入。
29.png

目前,存储引擎仍然只支持 Heap 表,相信不久的将来会支持更多的存储引擎。感兴趣的读者也可以尝试自行实现一个存储引擎。

postgres=> select * from pg_am;
 oid  | amname |      amhandler       | amtype
------+--------+----------------------+--------
    2 | heap   | heap_tableam_handler | t
  403 | btree  | bthandler            | i
  405 | hash   | hashhandler          | i
  783 | gist   | gisthandler          | i
 2742 | gin    | ginhandler           | i
 4000 | spgist | spghandler           | i
 3580 | brin   | brinhandler          | i
(7 rows)  

丰富的插件支持

阿里云 RDS PostgreSQL 12 提供了更加丰富的插件支持,满足广大用户在一些垂直领域和特殊场景下的需求,以下介绍一些较常用、有趣的插件,更多支持插件可以参考 PostgreSQL 的支持插件列表。

• roaringbitmap 将 roaringbitmap 作为一种内置数据类型,提供丰富的函数支持,使用 Roaring Bitmap 算法,极大提升位图计算性能。

• RDKit 支持 mol 数据类型(描述分子类型)和 fp 数据类型(描述分子指纹),支持化学分子计算和化学分子检索等功能。

• Ganos 阿里云自研时空数据引擎,支持对空间/时间数据进行高效的存储、索引、查询和分析计算。

• PASE 高性能向量检索插件,使用业界成熟稳定且高效的 ANN(Approximate nearest neighbor)检索算法,包括 IVFFlat 和HNSW 算法,通过这两种算法,可以在 PostgreSQL 数据库中实现极高速向量查询。

• zhparser 中文分词插件,助力实现中文的全文检索。

• oss_fdw 使用该插件可以将 OSS 中的数据加载到 PostgreSQL 中,也支持将 PostgreSQL 中的数据写入 OSS 中。

总结

RDS PostgreSQL 12 无论功能和性能都有很大提升,包括分区表查询性能优化,B-tree 索引空间优化和性能提升,参数方式选择 Prepare 语句执行计划,内置的、功能全面的 SQL/JSON 路径语言和更加丰富的插件支持。可插拔表访问接口作为未来支持多存储引擎的基础,意义重大,目前仍然只支持 Heap 表,用户测暂时不会有感知。
除本文介绍的特性外,该版本还有很多其他特性,如多列 MCV(Most-Common-Value)统计,内联 CTE(Common table expressions)等,文中未及介绍,感兴趣的读者可以参考相关文献或者在阿里云购买实例进行体验

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1月前
|
存储 监控 固态存储
在高并发环境下,如何优化 WAL 的写入性能?
在高并发环境下,如何优化 WAL 的写入性能?
|
17天前
|
SQL DataWorks 关系型数据库
阿里云 DataWorks 正式支持 SelectDB & Apache Doris 数据源,实现 MySQL 整库实时同步
阿里云数据库 SelectDB 版是阿里云与飞轮科技联合基于 Apache Doris 内核打造的现代化数据仓库,支持大规模实时数据上的极速查询分析。通过实时、统一、弹性、开放的核心能力,能够为企业提供高性价比、简单易用、安全稳定、低成本的实时大数据分析支持。SelectDB 具备世界领先的实时分析能力,能够实现秒级的数据实时导入与同步,在宽表、复杂多表关联、高并发点查等不同场景下,提供超越一众国际知名的同类产品的优秀性能,多次登顶 ClickBench 全球数据库分析性能排行榜。
|
16天前
|
缓存 监控 关系型数据库
如何根据监控结果调整 MySQL 数据库的参数以提高性能?
【10月更文挑战第28天】根据MySQL数据库的监控结果来调整参数以提高性能,需要综合考虑多个方面的因素
55 1
|
16天前
|
监控 关系型数据库 MySQL
如何监控和诊断 MySQL 数据库的性能问题?
【10月更文挑战第28天】监控和诊断MySQL数据库的性能问题是确保数据库高效稳定运行的关键
35 1
|
16天前
|
缓存 关系型数据库 MySQL
如何优化 MySQL 数据库的性能?
【10月更文挑战第28天】
38 1
|
18天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
85 1
|
23天前
|
存储 关系型数据库 MySQL
MySQL vs. PostgreSQL:选择适合你的开源数据库
在众多开源数据库中,MySQL和PostgreSQL无疑是最受欢迎的两个。它们都有着强大的功能、广泛的社区支持和丰富的生态系统。然而,它们在设计理念、性能特点、功能特性等方面存在着显著的差异。本文将从这三个方面对MySQL和PostgreSQL进行比较,以帮助您选择更适合您需求的开源数据库。
89 4
|
20天前
|
关系型数据库 MySQL PostgreSQL
postgresql和mysql中的limit使用方法
postgresql和mysql中的limit使用方法
35 1
|
28天前
|
存储 关系型数据库 MySQL
优化 MySQL 的锁机制以提高并发性能
【10月更文挑战第16天】优化 MySQL 锁机制需要综合考虑多个因素,根据具体的应用场景和需求进行针对性的调整。通过不断地优化和改进,可以提高数据库的并发性能,提升系统的整体效率。
49 1
|
1月前
|
缓存 弹性计算 NoSQL
新一期陪跑班开课啦!阿里云专家手把手带你体验高并发下利用云数据库缓存实现极速响应
新一期陪跑班开课啦!阿里云专家手把手带你体验高并发下利用云数据库缓存实现极速响应

相关产品

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