PostgreSQL 11 preview - 新功能, 分区表全局索引管理

本文涉及的产品
云原生数据库 PolarDB 分布式版,标准版 2核8GB
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
简介:

标签

PostgreSQL , 分区表 , 全局索引 , 分区索引 , 壳子索引


背景

PostgreSQL 10开始引入了原生支持的分区表,支持了range, list分区。

PostgreSQL 11对分区表的功能进行了增强,首先增加了hash分区表。其次,增加了分区表全局索引管理(PostgreSQL 10 分区表的主表上不支持索引,如果要建索引,不得不在每个分区上去定义,不太方便的。)。

以list分区为例,我们看看如何使用分区表的全局管理索引。

CREATE TABLE cities (  
    city_id      bigserial not null,  
    name         text not null,  
    population   bigint  
) PARTITION BY LIST (left(lower(name), 1));  
  
CREATE TABLE cities_ab  
    PARTITION OF cities (  
    CONSTRAINT city_id_nonzero CHECK (city_id != 0)  
) FOR VALUES IN ('a', 'b');  

创建分区表全局索引

1、创建全局索引

create index idx_cities_1 on cities(name);  

对现有分区,会自动添加这个索引

postgres=# \d+ cities  
                                                    Table "public.cities"  
   Column   |  Type  | Collation | Nullable |                 Default                 | Storage  | Stats target | Description   
------------+--------+-----------+----------+-----------------------------------------+----------+--------------+-------------  
 city_id    | bigint |           | not null | nextval('cities_city_id_seq'::regclass) | plain    |              |   
 name       | text   |           | not null |                                         | extended |              |   
 population | bigint |           |          |                                         | plain    |              |   
Partition key: LIST ("left"(lower(name), 1))  
Indexes:  
    "idx_cities_1" btree (name)  
Partitions: cities_ab FOR VALUES IN ('a', 'b')  
  
postgres=# \d cities_ab  
                               Table "public.cities_ab"  
   Column   |  Type  | Collation | Nullable |                 Default                   
------------+--------+-----------+----------+-----------------------------------------  
 city_id    | bigint |           | not null | nextval('cities_city_id_seq'::regclass)  
 name       | text   |           | not null |   
 population | bigint |           |          |   
Partition of: cities FOR VALUES IN ('a', 'b')  
Indexes:  
    "cities_ab_name_idx" btree (name)  
Check constraints:  
    "city_id_nonzero" CHECK (city_id <> 0)  

元数据中,主表索引显示为'I'类型,分区上的索引显示为'i'类型。

postgres=# select relname,relkind from pg_class where relname ~ 'citi';  
      relname       | relkind   
--------------------+---------  
 idx_cities_1       | I    # 分区表 - 主表上的索引  
 cities_ab          | r    # 分区表 - 分区表  
 cities_ab_name_idx | i    # 分区表 - 分区表上的索引  
 cities_city_id_seq | S    # 序列  
 cities             | p    # 分区表 - 主表  
(5 rows)  

2、新增分区,自动添加索引(如果这个分区上已经包含了同样定义的索引,那么会自动将这个索引attach到主表的索引中,而不会新建这个索引)

CREATE TABLE cities_cd  
    PARTITION OF cities (  
    CONSTRAINT city_id_nonzero CHECK (city_id != 0)  
) FOR VALUES IN ('c', 'd');  

自动索引如下(cities_cd_name_idx):

postgres=# \d+ cities_cd  
                                                   Table "public.cities_cd"  
   Column   |  Type  | Collation | Nullable |                 Default                 | Storage  | Stats target | Description   
------------+--------+-----------+----------+-----------------------------------------+----------+--------------+-------------  
 city_id    | bigint |           | not null | nextval('cities_city_id_seq'::regclass) | plain    |              |   
 name       | text   |           | not null |                                         | extended |              |   
 population | bigint |           |          |                                         | plain    |              |   
Partition of: cities FOR VALUES IN ('c', 'd')  
Partition constraint: (("left"(lower(name), 1) IS NOT NULL) AND ("left"(lower(name), 1) = ANY (ARRAY['c'::text, 'd'::text])))  
Indexes:  
    "cities_cd_name_idx" btree (name)  
Check constraints:  
    "city_id_nonzero" CHECK (city_id <> 0)  

创建分区表 主表全局壳子索引

有些时候,不希望所有的分区表都自动创建某些索引,但是又想统一管理全局索引,怎么办?

1、我们可以定义壳子索引,使用ONLY这个关键字,表示这个索引只建在当前这个表上。

postgres=# create index idx_cities_2 on only cities (population);  
CREATE INDEX  

这种方法创建出来的索引为INVALID索引。

postgres=# \d+ cities  
                                                    Table "public.cities"  
   Column   |  Type  | Collation | Nullable |                 Default                 | Storage  | Stats target | Description   
------------+--------+-----------+----------+-----------------------------------------+----------+--------------+-------------  
 city_id    | bigint |           | not null | nextval('cities_city_id_seq'::regclass) | plain    |              |   
 name       | text   |           | not null |                                         | extended |              |   
 population | bigint |           |          |                                         | plain    |              |   
Partition key: LIST ("left"(lower(name), 1))  
Indexes:  
    "idx_cities_1" btree (name)  
    "idx_cities_2" btree (population) INVALID  
Partitions: cities_ab FOR VALUES IN ('a', 'b'),  
            cities_cd FOR VALUES IN ('c', 'd')  

并且这个索引,也不会在分区上构建

postgres=# \d cities_ab  
                               Table "public.cities_ab"  
   Column   |  Type  | Collation | Nullable |                 Default                   
------------+--------+-----------+----------+-----------------------------------------  
 city_id    | bigint |           | not null | nextval('cities_city_id_seq'::regclass)  
 name       | text   |           | not null |   
 population | bigint |           |          |   
Partition of: cities FOR VALUES IN ('a', 'b')  
Indexes:  
    "cities_ab_name_idx" btree (name)  
Check constraints:  
    "city_id_nonzero" CHECK (city_id <> 0)  

将分区表分区索引绑定到主表全局索引

1、比如我们有一些分区想构建某个字段的索引,而其他分区确不想构建(比如对于某些分区的数据,我们不想按population字段查询,没有必要建立那些分区的索引)

postgres=# create index idx_cities_ab_2 on cities_ab (population);  
CREATE INDEX  

2、将这个分区上的索引,绑定到INVALID的全局壳子索引下面

postgres=# alter index idx_cities_2 attach partition idx_cities_ab_2;  
ALTER INDEX  
postgres=# \d+ cities  
                                                    Table "public.cities"  
   Column   |  Type  | Collation | Nullable |                 Default                 | Storage  | Stats target | Description   
------------+--------+-----------+----------+-----------------------------------------+----------+--------------+-------------  
 city_id    | bigint |           | not null | nextval('cities_city_id_seq'::regclass) | plain    |              |   
 name       | text   |           | not null |                                         | extended |              |   
 population | bigint |           |          |                                         | plain    |              |   
Partition key: LIST ("left"(lower(name), 1))  
Indexes:  
    "idx_cities_1" btree (name)  
    "idx_cities_2" btree (population) INVALID  
Partitions: cities_ab FOR VALUES IN ('a', 'b'),  
            cities_cd FOR VALUES IN ('c', 'd')  

3、那么现在的索引结构是这样的

postgres=# select relname,relkind from pg_class where relname ~ 'citi';  
      relname       | relkind   
--------------------+---------  
 idx_cities_1       | I  
 cities_ab          | r  
 cities_ab_name_idx | i  
 cities_cd_name_idx | i  
 cities_cd          | r  
 idx_cities_2       | I  
 idx_cities_ab_2    | i  
 cities_city_id_seq | S  
 cities             | p  
(9 rows)  

全局壳子索引的好处:

1、新增的分区表,不会自动创建这个索引,而是需要手工添加。满足一些特殊需求(例如有些分区不会检索某个字段,而其他分区需要检索,那么可以区别对待。)、

全局索引管理的好处

1、新增分区自动创建全局索引一样的索引(如果分区中已经包含了一个定义一致的本地索引,那么这个索引会自动attach到全局索引下,并被其管理)。

2、删除全局索引时,自动删除已经attach在这个全局索引下面的所有索引。

postgres=# drop index idx_cities_1;  
DROP INDEX  
postgres=# \d cities  
                                Table "public.cities"  
   Column   |  Type  | Collation | Nullable |                 Default                   
------------+--------+-----------+----------+-----------------------------------------  
 city_id    | bigint |           | not null | nextval('cities_city_id_seq'::regclass)  
 name       | text   |           | not null |   
 population | bigint |           |          |   
Partition key: LIST ("left"(lower(name), 1))  
Indexes:  
    "idx_cities_2" btree (population) INVALID  
Number of partitions: 2 (Use \d+ to list them.)  
  
postgres=# \d cities_ab  
                               Table "public.cities_ab"  
   Column   |  Type  | Collation | Nullable |                 Default                   
------------+--------+-----------+----------+-----------------------------------------  
 city_id    | bigint |           | not null | nextval('cities_city_id_seq'::regclass)  
 name       | text   |           | not null |   
 population | bigint |           |          |   
Partition of: cities FOR VALUES IN ('a', 'b')  
Indexes:  
    "idx_cities_ab_2" btree (population)  
Check constraints:  
    "city_id_nonzero" CHECK (city_id <> 0)  
  
postgres=# \d cities_cd  
                               Table "public.cities_cd"  
   Column   |  Type  | Collation | Nullable |                 Default                   
------------+--------+-----------+----------+-----------------------------------------  
 city_id    | bigint |           | not null | nextval('cities_city_id_seq'::regclass)  
 name       | text   |           | not null |   
 population | bigint |           |          |   
Partition of: cities FOR VALUES IN ('c', 'd')  
Check constraints:  
    "city_id_nonzero" CHECK (city_id <> 0)  
  

在另一个分区上,创建一个本地索引。并且不将这个索引attach到主表的全局壳子索引上。

那么在删除主表索引时,这个本地索引不会被自动删除。

postgres=# create index idx_cities_cd_2 on cities_cd (population );  
CREATE INDEX  
postgres=# drop index idx_cities_2;  
DROP INDEX  
postgres=# \d cities  
                                Table "public.cities"  
   Column   |  Type  | Collation | Nullable |                 Default                   
------------+--------+-----------+----------+-----------------------------------------  
 city_id    | bigint |           | not null | nextval('cities_city_id_seq'::regclass)  
 name       | text   |           | not null |   
 population | bigint |           |          |   
Partition key: LIST ("left"(lower(name), 1))  
Number of partitions: 2 (Use \d+ to list them.)  
  
postgres=# \d cities_ab  
                               Table "public.cities_ab"  
   Column   |  Type  | Collation | Nullable |                 Default                   
------------+--------+-----------+----------+-----------------------------------------  
 city_id    | bigint |           | not null | nextval('cities_city_id_seq'::regclass)  
 name       | text   |           | not null |   
 population | bigint |           |          |   
Partition of: cities FOR VALUES IN ('a', 'b')  
Check constraints:  
    "city_id_nonzero" CHECK (city_id <> 0)  
  
postgres=# \d cities_cd  
                               Table "public.cities_cd"  
   Column   |  Type  | Collation | Nullable |                 Default                   
------------+--------+-----------+----------+-----------------------------------------  
 city_id    | bigint |           | not null | nextval('cities_city_id_seq'::regclass)  
 name       | text   |           | not null |   
 population | bigint |           |          |   
Partition of: cities FOR VALUES IN ('c', 'd')  
Indexes:  
    "idx_cities_cd_2" btree (population)  
Check constraints:  
    "city_id_nonzero" CHECK (city_id <> 0)  

分区索引好处

分区索引不被全局管理,比较灵活,但是管理麻烦一些。

好处是不同的分区可以拥有不同的索引定义。在一些数据特殊管理的场景很灵活。

例如某些分区会经常检索A字段,但是某些分区确经常检索B字段,那么就可以为不同的分区创建不同的本地索引,而不是全局一起构建。可以节约一些成本,但是管理成本可能会上升。

元信息

元数据中,主表索引显示为'I'类型,分区上的索引显示为'i'类型。

postgres=# select relname,relkind from pg_class where relname ~ 'citi';  
      relname       | relkind   
--------------------+---------  
 idx_cities_1       | I    # 分区表 - 主表上的索引  
 cities_ab          | r    # 分区表 - 分区表  
 cities_ab_name_idx | i    # 分区表 - 分区表上的索引  
 cities_city_id_seq | S    # 序列  
 cities             | p    # 分区表 - 主表  
(5 rows)  

解释relkind中的含义:

I = partiton table global index,  分区表 - 主表上的索引  
r = ordinary table,               普通表  
i = index,                        普通表的索引,或者分区表分区上的本地索引  
S = sequence,                     序列  
t = TOAST table,                  切片表(变长字段压缩后超过BLOCK的1/4时,会存到切片表中)  
v = view,                         视图  
m = materialized view,            物化视图  
c = composite type,               自定义复合类型  
f = foreign table,                外部表  
p = partitioned table             分区表 - 主表  

小结

PostgreSQL 11 允许对分区表的主表创建索引,并内部支持了全局索引的管理机制(包括依赖、自动attach等)。

全局索引带来的好处,

1、当删除全局索引时,会将所有分区的索引自动删除。

2、当新增分区时,会自动创建与全局索引一致的索引(假设这个分区已有这样的索引,那么会自动将已有索引attach到全局索引下,便于管理)

3、对分区表创建索引时,会自动在所有分区下创建本地索引,并将分区本地索引ATTACH到全局索引下便于管理。

另外,全局索引还有一种壳子模式,即使用only关键字创建,它的好处:

1、使用ONLY关键字在分区表-主表上创建索引时,索引状态为INVALID,表示新建分区时,不会自动添加这个同类结构的索引,也不会自动ATTACH已有索引到这个全局索引下面。

2、使用全局索引的壳子模式,对不同的分区采用不同的索引,仅对需要用于管理的索引ATTACH到这个壳子中来管理。可以满足一些特殊业务场景(例如某些分区会经常检索A字段,但是某些分区确经常检索B字段,那么就可以为不同的分区创建不同的本地索引,而不是全局一起构建。可以节约一些成本,但是管理成本可能会上升。)。

PostgreSQL 11的全局索引使用非常灵活。

参考

https://www.postgresql.org/docs/devel/static/sql-alterindex.html

https://www.postgresql.org/docs/devel/static/sql-createindex.html

https://www.postgresql.org/docs/devel/static/catalog-pg-class.html

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
6月前
|
SQL 关系型数据库 PostgreSQL
把PostgreSQL的表导入SQLite
把PostgreSQL的表导入SQLite
87 0
|
3月前
|
监控 关系型数据库 数据库
PostgreSQL的索引优化策略?
【8月更文挑战第26天】PostgreSQL的索引优化策略?
89 1
|
3月前
|
SQL 关系型数据库 MySQL
SQL Server、MySQL、PostgreSQL:主流数据库SQL语法异同比较——深入探讨数据类型、分页查询、表创建与数据插入、函数和索引等关键语法差异,为跨数据库开发提供实用指导
【8月更文挑战第31天】SQL Server、MySQL和PostgreSQL是当今最流行的关系型数据库管理系统,均使用SQL作为查询语言,但在语法和功能实现上存在差异。本文将比较它们在数据类型、分页查询、创建和插入数据以及函数和索引等方面的异同,帮助开发者更好地理解和使用这些数据库。尽管它们共用SQL语言,但每个系统都有独特的语法规则,了解这些差异有助于提升开发效率和项目成功率。
325 0
|
4月前
|
关系型数据库 分布式数据库 数据库
PolarDB产品使用问题之如何进行PostgreSQL(简称PG)的全量和增量备份管理
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
|
3月前
|
关系型数据库 数据库 PostgreSQL
PostgreSQL索引维护看完这篇就够了
PostgreSQL索引维护看完这篇就够了
259 0
|
4月前
|
SQL 监控 关系型数据库
实时计算 Flink版操作报错合集之在设置监控PostgreSQL数据库时,将wal_level设置为logical,出现一些表更新和删除操作报错,怎么办
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
5月前
|
关系型数据库 PostgreSQL
postgresql如何将没有关联关系的两张表的字段合并
【6月更文挑战第2天】postgresql如何将没有关联关系的两张表的字段合并
132 3
|
5月前
|
存储 关系型数据库 数据库
经验大分享:PostgreSQL学习之【用户权限管理】说明
经验大分享:PostgreSQL学习之【用户权限管理】说明
56 0
|
5月前
|
SQL 关系型数据库 数据库连接
ClickHouse(20)ClickHouse集成PostgreSQL表引擎详细解析
ClickHouse的PostgreSQL引擎允许直接查询和插入远程PostgreSQL服务器的数据。`CREATE TABLE`语句示例展示了如何定义这样的表,包括服务器信息和权限。查询在只读事务中执行,简单筛选在PostgreSQL端处理,复杂操作在ClickHouse端完成。`INSERT`通过`COPY`命令在PostgreSQL事务中进行。注意,数组类型的处理和Nullable列的行为。示例展示了如何从PostgreSQL到ClickHouse同步数据。一系列的文章详细解释了ClickHouse的各种特性和表引擎。
164 0
|
5月前
|
SQL 关系型数据库 PostgreSQL
【sql】PostgreSQL物化视图表使用案例
【sql】PostgreSQL物化视图表使用案例
53 0

相关产品

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