PostgreSQL分区表原理、案例的灵活应用

2024-08-30 11:04

本文主要是介绍PostgreSQL分区表原理、案例的灵活应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

PostgreSQL分区表的灵活应用

通常情况下,扫描一个大表会很慢,需要扫描整张表格,如果能够把大表分拆成小表,查询数据的时猴,只扫描数据所属的小表,就能大大降低扫描时间,提高查询速度。

1、简介

PostgreSQL10之前的版本不支持内置分区表,若要实现分区功能,需通过继承的方式实现。

PostgreSQL 10.x 之前的版本提供了一种“手动”方式使用分区表的方式,需要使用继承 + 触发器的来实现分区表,步骤较为繁琐,需要定义附表、子表、子表的约束、创建子表索引,创建分区删除、修改,触发器等。

PostgreSQL 10.x 开始提供了内置分区表(内置是相对于 10.x 之前的手动方式)。内置分区简化了操作,将部分操作内置,最终简单三步就能够创建分区表。但是只支持范围分区(RANGE)和列表分区(LIST),11.x 版本添加了对 HASH 分区。

如果要充分使用分区表的查询优势,必须使用分区时的字段作为过滤条件。
除了在查询上的优势,分区表的使用也可提高删除数据的性能,因为删除一个分区要比删除分区上的所有数据要快的多。这些命令也完全避免了由批量DELETE造成的VACUUM负载。

概念:分区表就是根据分区策略,将数据数据分散到不同的子表中,并通过父表建立关联关系,从而实现数据物理上的分区。

文章目录

  • PostgreSQL分区表的灵活应用
    • 1、简介
    • 2、列表分区
    • 3、范围分区
    • 4、分区管理
    • 5、常用的分表方式,范围分区(包括分区表嵌套,添加、删除分区)
      • 5.1、创建主表
      • 5.2、创建分区表
      • 5.3、创建生成数据的函数
      • 5.4、插入数据到表格
      • 5.5、断开分区
      • 5.6、再创建与原来那个分区表一样的表结构,添加两个分区
      • 5.7、把原先那个总表的2021分区表数据导入现在分区表
      • 5.8、把这个分区表加入到到之前的分区表分区中
      • 5.9、查看当前的分区表信息

2、列表分区

--创建主表
CREATE TABLE info_list (id bigint NOT NULL,protocol varchar(16),ip varchar(50),create_time timestamp
) partition by list(create_time);--创建分区表
create table info_list20200801 partition of info_list for values in ('2020-08-01');
create table info_list20200802 partition of info_list for values in ('2020-08-02');
create table info_list20200803 partition of info_list for values in ('2020-08-03');
--分区表建索引
CREATE INDEX idx_info_list20200801 ON info_list20200801 (create_time);
CREATE INDEX idx_info_list20200802 ON info_list20200802 (create_time);
CREATE INDEX idx_info_list20200803 ON info_list20200803 (create_time);

3、范围分区

注意:如分表的范围为2020-08-01至2020-08-02,则包含前者,不包含后者。相当于时a<=create_time<b。

--1、创建主表(根据create_time进行范围分区)
CREATE TABLE info_range (id bigint NOT NULL,protocol varchar(16),ip varchar(50),create_time timestamp
) partition by range(create_time);
--2、创建分表(根据下面表范围,如果插入2020-08-04,则会报错;如范围为2020-08-01至2020-08-02,则包含前者,不包含后者。相当于时a<=create_time<b;)
create table info_range20200801 partition of info_range for values from ('2020-08-01') to ('2020-08-02');
create table info_range20200802 partition of info_range for values from ('2020-08-02') to ('2020-08-03');
create table info_range20200803 partition of info_range for values from ('2020-08-03') to ('2020-08-04');--3、创建索引
CREATE INDEX idx_info_range20200801 ON info_range20200801 (create_time);
CREATE INDEX idx_info_range20200802 ON info_range20200802 (create_time);
CREATE INDEX idx_info_range20200803 ON info_range20200803 (create_time);

4、分区管理

--断开分区
alter table info_range detach partition info_range20200803;
--连接分区
alter table info_range attach partition info_range20200803 for values from ('2020-08-03') to ('2020-08-04');
--删除分区
drop table info_range20200803;

PG11以上

哈希分区
通过为每个分区指定模数和余数来对表进行分区。每个分区所持有的行都满足:分区键的值除以为其指定的模数将产生为其指定的余数。

5、常用的分表方式,范围分区(包括分区表嵌套,添加、删除分区)

如给大表分区后的某个分区还是特别大,可以弄个二级分区,就像结构树那样嵌套下去(具体做法请参考5.5~5.8)

5.1、创建主表

CREATE TABLE sales_orders (order_id SERIAL,                       -- 订单ID,自动递增customer_id INT NOT NULL,              -- 客户ID,不允许为空order_date DATE NOT NULL,              -- 订单日期,不允许为空amount NUMERIC(10, 2) NOT NULL,        -- 订单金额,精确到小数点后两位,不允许为空status VARCHAR(20),                    -- 订单状态,例如 'completed' 或 'pending'CONSTRAINT sales_orders_pkey PRIMARY KEY (order_id, order_date) -- 设定主键约束,唯一标识每一条订单
)
PARTITION BY RANGE (order_date);          -- 根据订单日期进行范围分区

5.2、创建分区表


CREATE TABLE sales_orders_2021PARTITION OF sales_ordersFOR VALUES FROM ('2021-01-01') TO ('2021-12-31'); -- 2021年的订单分区CREATE TABLE sales_orders_2022PARTITION OF sales_ordersFOR VALUES FROM ('2022-01-01') TO ('2022-12-31'); -- 2022年的订单分区CREATE TABLE sales_orders_2023_q1_q2PARTITION OF sales_ordersFOR VALUES FROM ('2023-01-01') TO ('2023-06-30'); -- 2023年第一季度和第二季度的订单分区CREATE TABLE sales_orders_2023_q3_q4PARTITION OF sales_ordersFOR VALUES FROM ('2023-07-01') TO ('2023-12-31'); -- 2023年第三季度和第四季度的订单分区CREATE TABLE sales_orders_2024PARTITION OF sales_ordersFOR VALUES FROM ('2024-01-01') TO ('2024-12-31'); -- 2024年的订单分区

5.3、创建生成数据的函数

CREATE OR REPLACE FUNCTION insert_random_data(start_date DATE,   -- 起始日期end_date DATE,     -- 结束日期num_rows INT        -- 生成的记录数量
) RETURNS VOID LANGUAGE plpgsql AS $$
BEGININSERT INTO sales_orders (customer_id,   -- 客户IDorder_date,    -- 订单日期amount,        -- 订单金额status         -- 订单状态)SELECT(random() * 1000)::int AS customer_id,           -- 随机生成客户IDgenerate_series(start_date, end_date, '1 day'::interval)::date AS order_date, -- 从起始日期到结束日期生成日期系列(random() * 500 + 50)::numeric(10, 2) AS amount, -- 随机生成订单金额,范围在50到550之间CASE WHEN random() > 0.5 THEN 'completed' ELSE 'pending' END AS status -- 随机生成订单状态FROM generate_series(start_date, end_date, '1 day'::interval) -- 生成日期系列LIMIT num_rows;   -- 限制插入的记录数
END;
$$;

5.4、插入数据到表格

SELECT insert_random_data('2021-01-01', '2021-12-30', 50000);
SELECT insert_random_data('2022-01-01', '2022-12-30', 50000);test=# select count(*) from sales_orders;count  
--------100000
(1 row)test=# 

5.5、断开分区

alter table sales_orders detach partition sales_orders_2021;test=# select count(*) from sales_orders;count 
-------50000
(1 row)

5.6、再创建与原来那个分区表一样的表结构,添加两个分区

这种情况一般应用于,如给大表分区后的某个分区还是特别大,可以弄个二级分区,就像结构树那样嵌套下去

-- 创建2021年订单分区表
CREATE TABLE sales_orders_2021_p (order_id SERIAL,                    -- 订单ID,自动递增customer_id INT NOT NULL,           -- 客户ID,不允许为空order_date DATE NOT NULL,           -- 订单日期,不允许为空amount NUMERIC(10, 2) NOT NULL,     -- 订单金额,精确到小数点后两位,不允许为空status VARCHAR(20),                 -- 订单状态,例如 'completed' 或 'pending'CONSTRAINT sales_orders_2021_p_pkey PRIMARY KEY (order_id, order_date)  -- 主键约束
)
PARTITION BY RANGE (order_date);       -- 根据订单日期进行范围分区--新建两个分区
create table sales_orders_2021_p_1 partition of sales_orders_2021_p for VALUES FROM ('2021-01-01') TO ('2021-5-31');
create table sales_orders_2021_p_2 partition of sales_orders_2021_p for VALUES FROM ('2021-5-31') TO ('2021-12-31');

5.7、把原先那个总表的2021分区表数据导入现在分区表

insert into sales_orders_2021_p select * from sales_orders_2021;

5.8、把这个分区表加入到到之前的分区表分区中

test=# select count(*) from sales_orders;count 
-------50000
(1 row)alter table sales_orders ATTACH PARTITION sales_orders_2021_p FOR VALUES FROM ('2021-01-01') TO ('2021-12-31');test=# select count(*) from sales_orders;count  
--------100000
(1 row)

5.9、查看当前的分区表信息

--以下就是带有二级分区的分区表
test=# \d+ sales_orders;Partitioned table "public.sales_orders"Column    |         Type          | Collation | Nullable |                    Default                     | Storage  | Compression | Stats target | Description 
-------------+-----------------------+-----------+----------+------------------------------------------------+----------+-------------+--------------+-------------order_id    | integer               |           | not null | nextval('sales_orders_order_id_seq'::regclass) | plain    |             |              | customer_id | integer               |           | not null |                                                | plain    |             |              | order_date  | date                  |           | not null |                                                | plain    |             |              | amount      | numeric(10,2)         |           | not null |                                                | main     |             |              | status      | character varying(20) |           |          |                                                | extended |             |              | 
Partition key: RANGE (order_date)
Indexes:"sales_orders_pkey" PRIMARY KEY, btree (order_id, order_date)
Partitions: sales_orders_2021_p FOR VALUES FROM ('2021-01-01') TO ('2021-12-31'), PARTITIONED,sales_orders_2022 FOR VALUES FROM ('2022-01-01') TO ('2022-12-31'),sales_orders_2023_q1_q2 FOR VALUES FROM ('2023-01-01') TO ('2023-06-30'),sales_orders_2023_q3_q4 FOR VALUES FROM ('2023-07-01') TO ('2023-12-31'),sales_orders_2024 FOR VALUES FROM ('2024-01-01') TO ('2024-12-31')
test=# \d+;List of relationsSchema |               Name               |       Type        | Owner | Persistence | Access method |    Size    | Description 
--------+----------------------------------+-------------------+-------+-------------+---------------+------------+-------------public | sales_orders                     | partitioned table | fbase | permanent   |               | 0 bytes    | public | sales_orders_2021                | table             | fbase | permanent   | heap          | 3048 kB    | public | sales_orders_2021_p              | partitioned table | fbase | permanent   |               | 0 bytes    | public | sales_orders_2021_p_1            | table             | fbase | permanent   | heap          | 1248 kB    | public | sales_orders_2021_p_2            | table             | fbase | permanent   | heap          | 1768 kB    | public | sales_orders_2021_p_order_id_seq | sequence          | fbase | permanent   |               | 8192 bytes | public | sales_orders_2022                | table             | fbase | permanent   | heap          | 2976 kB    | public | sales_orders_2023_q1_q2          | table             | fbase | permanent   | heap          | 16 kB      | public | sales_orders_2023_q3_q4          | table             | fbase | permanent   | heap          | 16 kB      | public | sales_orders_2024                | table             | fbase | permanent   | heap          | 16 kB      | public | sales_orders_order_id_seq        | sequence          | fbase | permanent   |               | 8192 bytes | 
(11 rows)

这篇关于PostgreSQL分区表原理、案例的灵活应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1120637

相关文章

MyBatis分页查询实战案例完整流程

《MyBatis分页查询实战案例完整流程》MyBatis是一个强大的Java持久层框架,支持自定义SQL和高级映射,本案例以员工工资信息管理为例,详细讲解如何在IDEA中使用MyBatis结合Page... 目录1. MyBATis框架简介2. 分页查询原理与应用场景2.1 分页查询的基本原理2.1.1 分

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

ShardingProxy读写分离之原理、配置与实践过程

《ShardingProxy读写分离之原理、配置与实践过程》ShardingProxy是ApacheShardingSphere的数据库中间件,通过三层架构实现读写分离,解决高并发场景下数据库性能瓶... 目录一、ShardingProxy技术定位与读写分离核心价值1.1 技术定位1.2 读写分离核心价值二

深度解析Python中递归下降解析器的原理与实现

《深度解析Python中递归下降解析器的原理与实现》在编译器设计、配置文件处理和数据转换领域,递归下降解析器是最常用且最直观的解析技术,本文将详细介绍递归下降解析器的原理与实现,感兴趣的小伙伴可以跟随... 目录引言:解析器的核心价值一、递归下降解析器基础1.1 核心概念解析1.2 基本架构二、简单算术表达

深度解析Java @Serial 注解及常见错误案例

《深度解析Java@Serial注解及常见错误案例》Java14引入@Serial注解,用于编译时校验序列化成员,替代传统方式解决运行时错误,适用于Serializable类的方法/字段,需注意签... 目录Java @Serial 注解深度解析1. 注解本质2. 核心作用(1) 主要用途(2) 适用位置3

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

从原理到实战解析Java Stream 的并行流性能优化

《从原理到实战解析JavaStream的并行流性能优化》本文给大家介绍JavaStream的并行流性能优化:从原理到实战的全攻略,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的... 目录一、并行流的核心原理与适用场景二、性能优化的核心策略1. 合理设置并行度:打破默认阈值2. 避免装箱

Java 正则表达式的使用实战案例

《Java正则表达式的使用实战案例》本文详细介绍了Java正则表达式的使用方法,涵盖语法细节、核心类方法、高级特性及实战案例,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录一、正则表达式语法详解1. 基础字符匹配2. 字符类([]定义)3. 量词(控制匹配次数)4. 边

Python Counter 函数使用案例

《PythonCounter函数使用案例》Counter是collections模块中的一个类,专门用于对可迭代对象中的元素进行计数,接下来通过本文给大家介绍PythonCounter函数使用案例... 目录一、Counter函数概述二、基本使用案例(一)列表元素计数(二)字符串字符计数(三)元组计数三、C

PostgreSQL简介及实战应用

《PostgreSQL简介及实战应用》PostgreSQL是一种功能强大的开源关系型数据库管理系统,以其稳定性、高性能、扩展性和复杂查询能力在众多项目中得到广泛应用,本文将从基础概念讲起,逐步深入到高... 目录前言1. PostgreSQL基础1.1 PostgreSQL简介1.2 基础语法1.3 数据库