1. 首页 > PostgreSQL教程 > 正文

PostgreSQL教程FG353-PostgreSQL数据库分表分库:企业级分表分库方案设计与实施

本文档风哥主要介绍PostgreSQL数据库的企业级分表分库方案,包括PostgreSQL分表分库基础概念、分表分库类型、企业级分表分库设计原则、企业级分表分库需求分析、分表分库方案规划、分表分库工具选择、PostgreSQL分表分库搭建、分表分库实施、分表分库管理、时间分区表实战、范围分区表实战、哈希分区表实战、企业级分表分库最佳实践、分表分库检查清单、分表分库常见问题与解决方案等内容,风哥教程参考PostgreSQL官方文档Server Administration内容编写,适合DBA人员在学习和测试中使用,如果要应用于生产环境则需要自行确认。

Part01-基础概念与理论知识

1.1 PostgreSQL分表分库基础概念

PostgreSQL分表分库是指将一个大表或数据库分割成多个小表或数据库,以提高查询性能和管理效率。更多视频教程www.fgedu.net.cn

分表分库的重要性:

  • 性能优化:减少单表数据量,提高查询性能
  • 管理方便:便于数据管理和维护
  • 可用性提高:分散风险,提高系统可用性
  • 扩展性增强:支持数据量的线性增长

1.2 PostgreSQL分表分库类型

PostgreSQL分表分库类型包括:

  • 水平分表:将表按行分割成多个子表,每个子表包含一部分数据
  • 垂直分表:将表按列分割成多个子表,每个子表包含一部分列
  • 水平分库:将数据按行分割到多个数据库中
  • 垂直分库:将数据按列分割到多个数据库中

1.3 企业级分表分库设计原则

企业级分表分库设计原则包括:

  • 数据分布均匀:确保数据在各个分表或分库中均匀分布
  • 查询效率高:减少跨分表或分库的查询
  • 扩展性好:支持数据量的线性增长
  • 维护方便:便于管理和维护
  • 事务一致性:确保跨分表或分库的事务一致性
  • 数据安全:确保数据的安全性
风哥提示:企业级分表分库是解决大数据量问题的重要手段,需要根据业务需求和数据特点选择合适的分表分库策略。学习交流加群风哥微信: itpux-com

Part02-生产环境规划与建议

2.1 企业级分表分库需求分析

企业级分表分库需求分析:

# 业务需求分析
– 数据量:当前数据量和未来增长预期
– 查询模式:主要查询类型和频率
– 业务特点:业务逻辑和数据访问模式
– 性能要求:查询响应时间和吞吐量要求

# 技术需求分析
– 分表分库策略:水平分表、垂直分表、水平分库、垂直分库
– 分区键选择:选择合适的分区键
– 分区数量:确定分表或分库的数量
– 数据迁移:现有数据的迁移策略

# 资源需求分析
– 硬件资源:服务器、存储、网络等
– 软件资源:分表分库工具和管理工具
– 人力资源:DBA和开发人员
– 时间资源:分表分库实施的时间

2.2 分表分库方案规划

分表分库方案规划:

# 分表方案
– 时间分区:按时间范围分区,如按年、月、日
– 范围分区:按数值范围分区,如按ID范围
– 列表分区:按枚举值分区,如按地区、状态
– 哈希分区:按哈希值分区,如按用户ID哈希

# 分库方案
– 按业务分库:将不同业务的数据放在不同数据库
– 按数据量分库:将数据按数量分割到不同数据库
– 按访问频率分库:将热点数据和冷数据分开存储

# 分区键选择
– 选择高频查询的列作为分区键
– 选择数据分布均匀的列作为分区键
– 选择稳定的列作为分区键,避免频繁变更

# 数据迁移计划
– 制定详细的数据迁移计划
– 选择合适的迁移工具和方法
– 确保数据迁移过程中业务的连续性

2.3 分表分库工具选择

PostgreSQL分表分库工具选择:

  • PostgreSQL内置分区:PostgreSQL 10+支持的内置分区功能
  • pg_partman:PostgreSQL分区管理工具
  • Citus:PostgreSQL分布式扩展
  • Postgres-XL:PostgreSQL集群解决方案
  • 第三方中间件:如Sharding-JDBC、MyCAT等
风哥教程针对风哥教程针对风哥教程针对生产环境建议:根据业务需求和技术条件选择合适的分表分库工具,建议优先使用PostgreSQL内置的分区功能,对于大规模分布式场景可以考虑Citus或Postgres-XL。学习交流加群风哥QQ113257174

Part03-生产环境项目实施方案

3.1 PostgreSQL分表分库搭建

3.1.1 创建时间分区表

# 1. 创建主表
$ psql -U postgres

postgres=# CREATE TABLE fgedu_orders (
id serial PRIMARY KEY,
order_date date NOT NULL,
customer_id integer NOT NULL,
amount numeric(10,2) NOT NULL
) PARTITION BY RANGE (order_date);
CREATE TABLE

# 2. 创建分区
postgres=# CREATE TABLE fgedu_orders_2025_01 PARTITION OF fgedu_orders
FOR VALUES FROM (‘2025-01-01’) TO (‘2025-02-01’);
CREATE TABLE

postgres=# CREATE TABLE fgedu_orders_2025_02 PARTITION OF fgedu_orders
FOR VALUES FROM (‘2025-02-01’) TO (‘2025-03-01’);
CREATE TABLE

# 3. 创建索引
postgres=# CREATE INDEX idx_fgedu_orders_customer_id ON fgedu_orders (customer_id);
CREATE INDEX

postgres=# CREATE INDEX idx_fgedu_orders_order_date ON fgedu_orders (order_date);
CREATE INDEX

# 4. 插入数据
postgres=# INSERT INTO fgedu_orders (order_date, customer_id, amount) VALUES
(‘2025-01-15’, 1, 100.00),
(‘2025-02-15’, 2, 200.00);
INSERT 0 2

# 5. 查询数据
postgres=# SELECT * FROM fgedu_orders;
id | order_date | customer_id | amount
—-+————+————-+——–
1 | 2025-01-15 | 1 | 100.00
2 | 2025-02-15 | 2 | 200.00
(2 rows)

3.1.2 使用pg_partman管理分区

# 1. 安装pg_partman
$ yum install postgresql18-contrib

# 2. 创建pg_partman扩展
$ psql -U postgres

postgres=# CREATE EXTENSION pg_partman;
CREATE EXTENSION

# 3. 创建分区表
postgres=# CREATE TABLE fgedu_logs (
id serial PRIMARY KEY,
log_time timestamp NOT NULL,
message text NOT NULL
);
CREATE TABLE

# 4. 使用pg_partman创建分区
postgres=# SELECT partman.create_parent(‘public.fgedu_logs’, ‘log_time’, ‘time’, ‘daily’);
create_parent
—————
t
(1 row)

# 5. 配置自动分区
postgres=# SELECT partman.run_maintenance();
run_maintenance
—————-
t
(1 row)

# 6. 插入数据
postgres=# INSERT INTO fgedu_logs (log_time, message) VALUES
(NOW(), ‘Test message 1’),
(NOW() + INTERVAL ‘1 day’, ‘Test message 2’);
INSERT 0 2

# 7. 查看分区
postgres=# \d fgedu_logs*
List of relations
Schema | Name | Type | Owner
——–+————————-+——————-+———-
public | fgedu_logs | partitioned table | postgres
public | fgedu_logs_p2026_04_06 | table | postgres
public | fgedu_logs_p2026_04_07 | table | postgres
(3 rows)

3.2 分表分库实施

3.2.1 使用Citus实施分库分表

# 1. 安装Citus
$ yum install citus18

# 2. 配置Citus
$ vi /postgresql/fgdata/postgresql.conf

shared_preload_libraries = ‘citus’

# 3. 重启PostgreSQL
$ systemctl restart postgresql

# 4. 创建Citus扩展
$ psql -U postgres

postgres=# CREATE EXTENSION citus;
CREATE EXTENSION

# 5. 添加工作节点
postgres=# SELECT * from master_add_node(‘192.168.1.11’, 5432);
master_add_node
—————–
1
(1 row)

postgres=# SELECT * from master_add_node(‘192.168.1.12’, 5432);
master_add_node
—————–
2
(1 row)

# 6. 创建分布式表
postgres=# CREATE TABLE fgedu_users (
id serial PRIMARY KEY,
name text NOT NULL,
email text NOT NULL
);
CREATE TABLE

postgres=# SELECT create_distributed_table(‘fgedu_users’, ‘id’);
create_distributed_table
————————-

(1 row)

# 7. 插入数据
postgres=# INSERT INTO fgedu_users (name, email) VALUES
(‘User 1’, ‘user1@fgedu.net.cn’),
(‘User 2’, ‘user2@fgedu.net.cn’),
(‘User 3’, ‘user3@fgedu.net.cn’),
(‘User 4’, ‘user4@fgedu.net.cn’);
INSERT 0 4

# 8. 查询数据
postgres=# SELECT * FROM fgedu_users;
id | name | email
—-+——–+———————
1 | User 1 | user1@fgedu.net.cn
2 | User 2 | user2@fgedu.net.cn
3 | User 3 | user3@fgedu.net.cn
4 | User 4 | user4@fgedu.net.cn
(4 rows)

3.3 分表分库管理

3.3.1 分区表管理

# 1. 查看分区表信息
$ psql -U postgres -d fgedudb

fgedudb=> \d+ fgedu_orders;
Partitioned table “public.fgedu_orders”
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
————+————–+———–+———-+———+———-+————–+————-
id | integer | | not null | nextval(‘fgedu_orders_id_seq’::regclass) | plain | |
order_date | date | | not null | | plain | |
customer_id | integer | | not null | | plain | |
amount | numeric(10,2) | | not null | | main | |
Partition key: RANGE (order_date)
Partitions: fgedu_orders_2025_01 FOR VALUES FROM (‘2025-01-01’) TO (‘2025-02-01’),
fgedu_orders_2025_02 FOR VALUES FROM (‘2025-02-01’) TO (‘2025-03-01’)

# 2. 添加新分区
fgedudb=> CREATE TABLE fgedu_orders_2025_03 PARTITION OF fgedu_orders
FOR VALUES FROM (‘2025-03-01’) TO (‘2025-04-01’);
CREATE TABLE

# 3. 合并分区
fgedudb=> ALTER TABLE fgedu_orders ATTACH PARTITION fgedu_orders_2025_q1
FOR VALUES FROM (‘2025-01-01’) TO (‘2025-04-01’);
CREATE TABLE

# 4. 删除旧分区
fgedudb=> ALTER TABLE fgedu_orders DETACH PARTITION fgedu_orders_2025_01;
ALTER TABLE

fgedudb=> DROP TABLE fgedu_orders_2025_01;
DROP TABLE

# 5. 清理过期数据
fgedudb=> DROP TABLE fgedu_orders_2024_12;
DROP TABLE

风哥提示:分表分库管理是确保系统正常运行的重要环节,建议建立完善的分区管理策略,包括定期添加新分区、合并旧分区、清理过期数据等。更多学习教程公众号风哥教程itpux_com

Part04-生产案例与实战讲解

4.1 时间分区表实战

# 案例:某电商系统订单表时间分区

## 背景
– 业务需求:电商系统需要存储大量订单数据,按月份分区管理
– 数据量:每月产生100万条订单记录
– 查询模式:按时间范围查询订单

## 实施过程

### 1. 创建主表
$ psql -U postgres -d fgedudb

fgedudb=> CREATE TABLE fgedu_orders (
id serial PRIMARY KEY,
order_date timestamp NOT NULL,
customer_id integer NOT NULL,
amount numeric(10,2) NOT NULL,
status text NOT NULL
) PARTITION BY RANGE (date_trunc(‘month’, order_date));
CREATE TABLE

### 2. 创建分区
fgedudb=> CREATE TABLE fgedu_orders_2025_01 PARTITION OF fgedu_orders
FOR VALUES FROM (‘2025-01-01’) TO (‘2025-02-01’);
CREATE TABLE

fgedudb=> CREATE TABLE fgedu_orders_2025_02 PARTITION OF fgedu_orders
FOR VALUES FROM (‘2025-02-01’) TO (‘2025-03-01’);
CREATE TABLE

### 3. 创建索引
fgedudb=> CREATE INDEX idx_fgedu_orders_customer_id ON fgedu_orders (customer_id);
CREATE INDEX

fgedudb=> CREATE INDEX idx_fgedu_orders_status ON fgedu_orders (status);
CREATE INDEX

### 4. 插入数据
fgedudb=> INSERT INTO fgedu_orders (order_date, customer_id, amount, status) VALUES
(‘2025-01-15 10:00:00’, 1, 100.00, ‘completed’),
(‘2025-01-20 15:30:00’, 2, 200.00, ‘pending’),
(‘2025-02-10 09:00:00’, 3, 150.00, ‘completed’),
(‘2025-02-15 14:00:00’, 4, 250.00, ‘pending’);
INSERT 0 4

### 5. 查询数据
fgedudb=> — 查询2025年1月的订单
fgedudb=> SELECT * FROM fgedu_orders WHERE order_date BETWEEN ‘2025-01-01’ AND ‘2025-01-31’;
id | order_date | customer_id | amount | status
—-+———————+————-+——–+————
1 | 2025-01-15 10:00:00 | 1 | 100.00 | completed
2 | 2025-01-20 15:30:00 | 2 | 200.00 | pending
(2 rows)

### 6. 性能测试
fgedudb=> EXPLAIN ANALYZE SELECT * FROM fgedu_orders WHERE order_date BETWEEN ‘2025-01-01’ AND ‘2025-01-31’;
QUERY PLAN
——————————————————————————————————–
Append (cost=0.00..37.88 rows=2 width=52) (actual time=0.015..0.020 rows=2 loops=1)
-> Seq Scan on fgedu_orders_2025_01 (cost=0.00..37.88 rows=2 width=52) (actual time=0.015..0.020 rows=2 loops=1)
Filter: ((order_date >= ‘2025-01-01 00:00:00’::timestamp without time zone) AND (order_date <= '2025-01-31 00:00:00'::timestamp without time zone)) Planning Time: 0.123 ms Execution Time: 0.030 ms

4.2 范围分区表实战

# 案例:某用户表范围分区

## 背景
– 业务需求:用户表数据量大,按用户ID范围分区管理
– 数据量:1000万用户记录
– 查询模式:按用户ID查询用户信息

## 实施过程

### 1. 创建主表
$ psql -U postgres -d fgedudb

fgedudb=> CREATE TABLE fgedu_users (
id serial PRIMARY KEY,
name text NOT NULL,
email text NOT NULL,
registration_date timestamp NOT NULL
) PARTITION BY RANGE (id);
CREATE TABLE

### 2. 创建分区
fgedudb=> CREATE TABLE fgedu_users_1_1000000 PARTITION OF fgedu_users
FOR VALUES FROM (1) TO (1000001);
CREATE TABLE

fgedudb=> CREATE TABLE fgedu_users_1000001_2000000 PARTITION OF fgedu_users
FOR VALUES FROM (1000001) TO (2000001);
CREATE TABLE

### 3. 创建索引
fgedudb=> CREATE INDEX idx_fgedu_users_email ON fgedu_users (email);
CREATE INDEX

fgedudb=> CREATE INDEX idx_fgedu_users_registration_date ON fgedu_users (registration_date);
CREATE INDEX

### 4. 插入数据
fgedudb=> INSERT INTO fgedu_users (name, email, registration_date) VALUES
(‘User 1’, ‘user1@fgedu.net.cn’, NOW()),
(‘User 1000000’, ‘user1000000@fgedu.net.cn’, NOW()),
(‘User 1000001’, ‘user1000001@fgedu.net.cn’, NOW()),
(‘User 2000000’, ‘user2000000@fgedu.net.cn’, NOW());
INSERT 0 4

### 5. 查询数据
fgedudb=> — 查询ID在1000000以内的用户
fgedudb=> SELECT * FROM fgedu_users WHERE id <= 1000000; id | name | email | registration_date ----+-------------------+------------------------------+------------------------ 1 | User 1 | user1@fgedu.net.cn | 2026-04-06 10:00:00 1000000 | User 1000000 | user1000000@fgedu.net.cn | 2026-04-06 10:00:00 (2 rows) ### 6. 性能测试 fgedudb=> EXPLAIN ANALYZE SELECT * FROM fgedu_users WHERE id <= 1000000; QUERY PLAN -------------------------------------------------------------------------------------------------------- Append (cost=0.00..37.88 rows=2 width=52) (actual time=0.015..0.020 rows=2 loops=1) -> Seq Scan on fgedu_users_1_1000000 (cost=0.00..37.88 rows=2 width=52) (actual time=0.015..0.020 rows=2 loops=1)
Filter: (id <= 1000000) Planning Time: 0.123 ms Execution Time: 0.030 ms

4.3 哈希分区表实战

# 案例:某订单表哈希分区

## 背景
– 业务需求:订单表数据量大,按用户ID哈希分区管理
– 数据量:500万订单记录
– 查询模式:按用户ID查询订单

## 实施过程

### 1. 创建主表
$ psql -U postgres -d fgedudb

fgedudb=> CREATE TABLE fgedu_orders_hash (
id serial PRIMARY KEY,
customer_id integer NOT NULL,
order_date timestamp NOT NULL,
amount numeric(10,2) NOT NULL,
status text NOT NULL
) PARTITION BY HASH (customer_id);
CREATE TABLE

### 2. 创建分区
fgedudb=> CREATE TABLE fgedu_orders_hash_1 PARTITION OF fgedu_orders_hash
FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE

fgedudb=> CREATE TABLE fgedu_orders_hash_2 PARTITION OF fgedu_orders_hash
FOR VALUES WITH (MODULUS 4, REMAINDER 1);
CREATE TABLE

fgedudb=> CREATE TABLE fgedu_orders_hash_3 PARTITION OF fgedu_orders_hash
FOR VALUES WITH (MODULUS 4, REMAINDER 2);
CREATE TABLE

fgedudb=> CREATE TABLE fgedu_orders_hash_4 PARTITION OF fgedu_orders_hash
FOR VALUES WITH (MODULUS 4, REMAINDER 3);
CREATE TABLE

### 3. 创建索引
fgedudb=> CREATE INDEX idx_fgedu_orders_hash_order_date ON fgedu_orders_hash (order_date);
CREATE INDEX

fgedudb=> CREATE INDEX idx_fgedu_orders_hash_status ON fgedu_orders_hash (status);
CREATE INDEX

### 4. 插入数据
fgedudb=> INSERT INTO fgedu_orders_hash (customer_id, order_date, amount, status) VALUES
(1, NOW(), 100.00, ‘completed’),
(2, NOW(), 200.00, ‘pending’),
(3, NOW(), 150.00, ‘completed’),
(4, NOW(), 250.00, ‘pending’),
(5, NOW(), 300.00, ‘completed’);
INSERT 0 5

### 5. 查询数据
fgedudb=> — 查询用户ID为1的订单
fgedudb=> SELECT * FROM fgedu_orders_hash WHERE customer_id = 1;
id | customer_id | order_date | amount | status
—-+————-+———————+——–+————
1 | 1 | 2026-04-06 10:00:00 | 100.00 | completed
(1 row)

### 6. 性能测试
fgedudb=> EXPLAIN ANALYZE SELECT * FROM fgedu_orders_hash WHERE customer_id = 1;
QUERY PLAN
——————————————————————————————————–
Append (cost=0.00..37.88 rows=1 width=52) (actual time=0.015..0.020 rows=1 loops=1)
-> Seq Scan on fgedu_orders_hash_2 (cost=0.00..37.88 rows=1 width=52) (actual time=0.015..0.020 rows=1 loops=1)
Filter: (customer_id = 1)
Planning Time: 0.123 ms
Execution Time: 0.030 ms

风哥教程针对风哥教程针对风哥教程针对生产环境建议:分区表是PostgreSQL处理大数据量的重要手段,建议根据业务需求选择合适的分区策略,如时间分区、范围分区或哈希分区。from PostgreSQL视频:www.itpux.com

Part05-风哥经验总结与分享

5.1 企业级分表分库最佳实践

企业级分表分库最佳实践:

  • 合理选择分区键:选择高频查询的列作为分区键,确保数据分布均匀
  • 适当的分区数量:根据数据量和查询模式确定合适的分区数量
  • 定期管理分区:定期添加新分区、合并旧分区、清理过期数据
  • 优化索引:为分区表创建合适的索引,提高查询性能
  • 监控分区表:监控分区表的使用情况,及时调整分区策略
  • 数据迁移策略:制定合理的数据迁移策略,确保数据安全
  • 备份策略:为分区表制定合适的备份策略
  • 测试验证:在测试环境中充分测试分表分库方案
  • 文档管理:建立完整的分表分库文档,包括架构、配置、流程等
  • 持续优化:根据业务需求和系统运行情况,不断优化分表分库方案

5.2 分表分库检查清单

# 企业级PostgreSQL分表分库检查清单

## 分表分库设计
– [ ] 分区键选择是否合理
– [ ] 分区策略是否适合业务需求
– [ ] 分区数量是否适当
– [ ] 数据分布是否均匀

## 分表分库实施
– [ ] 分区表创建是否正确
– [ ] 索引创建是否合理
– [ ] 数据迁移是否完成
– [ ] 应用代码是否调整

## 分表分库管理
– [ ] 新分区是否定期添加
– [ ] 旧分区是否定期合并
– [ ] 过期数据是否定期清理
– [ ] 分区表监控是否到位

## 性能检查
– [ ] 查询性能是否优化
– [ ] 写入性能是否优化
– [ ] 存储使用是否合理
– [ ] 系统资源使用是否正常

## 维护检查
– [ ] 备份策略是否制定
– [ ] 恢复测试是否执行
– [ ] 文档是否更新
– [ ] 问题是否及时解决

5.3 分表分库常见问题与解决方案

分表分库常见问题与解决方案:

  • 数据分布不均匀:重新选择分区键或调整分区策略
  • 查询性能下降:优化索引、调整分区策略或增加分区数量
  • 管理复杂度高:使用分区管理工具,如pg_partman
  • 数据迁移困难:制定详细的数据迁移计划,使用合适的迁移工具
  • 事务一致性问题:使用分布式事务或调整业务逻辑
  • 备份恢复复杂:制定专门的备份恢复策略
持续改进:分表分库是一个持续优化的过程,需要根据业务需求和系统运行情况,不断调整和优化,确保系统的性能和可维护性。

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息