PostgreSQL教程FG344-PostgreSQL数据库分表分库:企业级分表分库方案设计与实施
本文档风哥主要介绍PostgreSQL数据库的企业级分表分库方案,包括PostgreSQL分表分库基础概念、分表分库类型、企业级分表分库设计原则、企业级分表分库需求分析、分表分库方案规划、分表分库工具选择、PostgreSQL分区表配置、分库分表实施、分表分库管理、时间分区表实战、范围分区表实战、列表分区表实战、企业级分表分库最佳实践、分表分库检查清单、分表分库常见问题与解决方案等内容,风哥教程参考PostgreSQL官方文档Server Administration内容编写,适合DBA人员在学习和测试中使用,如果要应用于生产环境则需要自行确认。
Part01-基础概念与理论知识
1.1 PostgreSQL分表分库基础概念
PostgreSQL分表分库是指将一个大表或数据库分割成多个小表或数据库,以提高查询性能和管理效率。更多视频教程www.fgedu.net.cn
- 性能优化:减少单表数据量,提高查询性能
- 管理方便:便于数据管理和维护
- 可用性提高:分散风险,提高系统可用性
- 扩展性增强:支持数据量的线性增长
1.2 PostgreSQL分表分库类型
PostgreSQL分表分库类型包括:
- 水平分表:将表按行分割成多个子表,每个子表包含一部分数据
- 垂直分表:将表按列分割成多个子表,每个子表包含一部分列
- 水平分库:将数据按行分割到多个数据库中
- 垂直分库:将数据按列分割到多个数据库中
1.3 企业级分表分库设计原则
企业级分表分库设计原则包括:
- 数据分布均匀:确保数据在各个分表或分库中均匀分布
- 查询效率高:减少跨分表或分库的查询
- 扩展性好:支持数据量的线性增长
- 维护方便:便于管理和维护
- 事务一致性:确保跨分表或分库的事务一致性
- 数据安全:确保数据的安全性
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等
Part03-生产环境项目实施方案
3.1 PostgreSQL分区表配置
3.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管理分区
$ 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实施分库分表
$ 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 分区表管理
$ psql -U postgres
postgres=# \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. 添加新分区
postgres=# CREATE TABLE fgedu_orders_2025_03 PARTITION OF fgedu_orders
FOR VALUES FROM (‘2025-03-01’) TO (‘2025-04-01’);
CREATE TABLE
# 3. 合并分区
postgres=# ALTER TABLE fgedu_orders ATTACH PARTITION fgedu_orders_2025_q1
FOR VALUES FROM (‘2025-01-01’) TO (‘2025-04-01’);
CREATE TABLE
# 4. 删除旧分区
postgres=# ALTER TABLE fgedu_orders DETACH PARTITION fgedu_orders_2025_01;
ALTER TABLE
postgres=# DROP TABLE fgedu_orders_2025_01;
DROP TABLE
# 5. 清理过期数据
postgres=# DROP TABLE fgedu_orders_2024_12;
DROP TABLE
Part04-生产案例与实战讲解
4.1 时间分区表实战
# 电商系统的订单表,按月份分区,方便管理和查询历史数据
# 2. 实施步骤
# 2.1 创建主表
$ psql -U postgres
postgres=# 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.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
# 2.3 创建索引
postgres=# CREATE INDEX idx_fgedu_orders_customer_id ON fgedu_orders (customer_id);
CREATE INDEX
postgres=# CREATE INDEX idx_fgedu_orders_status ON fgedu_orders (status);
CREATE INDEX
# 2.4 插入数据
postgres=# 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
# 2.5 查询数据
postgres=# — 查询2025年1月的订单
postgres=# 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)
# 2.6 性能测试
postgres=# 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范围分区,方便管理和查询用户数据
# 2. 实施步骤
# 2.1 创建主表
$ psql -U postgres
postgres=# 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.2 创建分区
postgres=# CREATE TABLE fgedu_users_1_10000 PARTITION OF fgedu_users
FOR VALUES FROM (1) TO (10001);
CREATE TABLE
postgres=# CREATE TABLE fgedu_users_10001_20000 PARTITION OF fgedu_users
FOR VALUES FROM (10001) TO (20001);
CREATE TABLE
# 2.3 创建索引
postgres=# CREATE INDEX idx_fgedu_users_email ON fgedu_users (email);
CREATE INDEX
postgres=# CREATE INDEX idx_fgedu_users_registration_date ON fgedu_users (registration_date);
CREATE INDEX
# 2.4 插入数据
postgres=# INSERT INTO fgedu_users (name, email, registration_date) VALUES
(‘User 1’, ‘user1@fgedu.net.cn’, ‘2025-01-01’),
(‘User 10000’, ‘user10000@fgedu.net.cn’, ‘2025-01-15’),
(‘User 10001’, ‘user10001@fgedu.net.cn’, ‘2025-02-01’),
(‘User 20000’, ‘user20000@fgedu.net.cn’, ‘2025-02-15’);
INSERT 0 4
# 2.5 查询数据
postgres=# — 查询ID在10000以内的用户
postgres=# SELECT * FROM fgedu_users WHERE id <= 10000;
id | name | email | registration_date
----+------------+-----------------------+-------------------
1 | User 1 | user1@fgedu.net.cn | 2025-01-01 00:00:00
10000 | User 10000 | user10000@fgedu.net.cn | 2025-01-15 00:00:00
(2 rows)
# 2.6 性能测试
postgres=# EXPLAIN ANALYZE SELECT * FROM fgedu_users WHERE id <= 10000;
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_10000 (cost=0.00..37.88 rows=2 width=52) (actual time=0.015..0.020 rows=2 loops=1)
Filter: (id <= 10000)
Planning Time: 0.123 ms
Execution Time: 0.030 ms
4.3 列表分区表实战
# 订单表,按订单状态分区,方便管理和查询不同状态的订单
# 2. 实施步骤
# 2.1 创建主表
$ psql -U postgres
postgres=# CREATE TABLE fgedu_orders_status (
id serial PRIMARY KEY,
order_id integer NOT NULL,
status text NOT NULL,
update_time timestamp NOT NULL
) PARTITION BY LIST (status);
CREATE TABLE
# 2.2 创建分区
postgres=# CREATE TABLE fgedu_orders_status_completed PARTITION OF fgedu_orders_status
FOR VALUES IN (‘completed’);
CREATE TABLE
postgres=# CREATE TABLE fgedu_orders_status_pending PARTITION OF fgedu_orders_status
FOR VALUES IN (‘pending’);
CREATE TABLE
postgres=# CREATE TABLE fgedu_orders_status_cancelled PARTITION OF fgedu_orders_status
FOR VALUES IN (‘cancelled’);
CREATE TABLE
# 2.3 创建索引
postgres=# CREATE INDEX idx_fgedu_orders_status_order_id ON fgedu_orders_status (order_id);
CREATE INDEX
postgres=# CREATE INDEX idx_fgedu_orders_status_update_time ON fgedu_orders_status (update_time);
CREATE INDEX
# 2.4 插入数据
postgres=# INSERT INTO fgedu_orders_status (order_id, status, update_time) VALUES
(1, ‘completed’, ‘2025-01-15 10:00:00’),
(2, ‘pending’, ‘2025-01-15 11:00:00’),
(3, ‘cancelled’, ‘2025-01-15 12:00:00’),
(4, ‘completed’, ‘2025-01-15 13:00:00’);
INSERT 0 4
# 2.5 查询数据
postgres=# — 查询已完成的订单
postgres=# SELECT * FROM fgedu_orders_status WHERE status = ‘completed’;
id | order_id | status | update_time
—-+———-+————+———————
1 | 1 | completed | 2025-01-15 10:00:00
4 | 4 | completed | 2025-01-15 13:00:00
(2 rows)
# 2.6 性能测试
postgres=# EXPLAIN ANALYZE SELECT * FROM fgedu_orders_status WHERE status = ‘completed’;
QUERY PLAN
——————————————————————————————————–
Append (cost=0.00..37.88 rows=2 width=40) (actual time=0.015..0.020 rows=2 loops=1)
-> Seq Scan on fgedu_orders_status_completed (cost=0.00..37.88 rows=2 width=40) (actual time=0.015..0.020 rows=2 loops=1)
Filter: (status = ‘completed’::text)
Planning Time: 0.123 ms
Execution Time: 0.030 ms
Part05-风哥经验总结与分享
5.1 企业级分表分库最佳实践
企业级分表分库最佳实践:
- 合理选择分区键:选择高频查询的列作为分区键,确保数据分布均匀
- 适当的分区数量:根据数据量和查询模式确定合适的分区数量
- 定期管理分区:定期添加新分区、合并旧分区、清理过期数据
- 优化索引:为分区表创建合适的索引,提高查询性能
- 监控分区表:监控分区表的使用情况,及时调整分区策略
- 数据迁移策略:制定合理的数据迁移策略,确保数据安全
- 备份策略:为分区表制定合适的备份策略
- 测试验证:在测试环境中充分测试分表分库方案
- 文档管理:建立完整的分表分库文档,包括架构、配置、流程等
- 持续优化:根据业务需求和系统运行情况,不断优化分表分库方案
5.2 分表分库检查清单
## 分表分库设计检查
– [ ] 分区键选择是否合理
– [ ] 分区策略是否适合业务需求
– [ ] 分区数量是否适当
– [ ] 数据分布是否均匀
## 分表分库实施检查
– [ ] 分区表创建是否正确
– [ ] 索引创建是否合理
– [ ] 数据迁移是否完成
– [ ] 应用代码是否调整
## 分表分库管理检查
– [ ] 新分区是否定期添加
– [ ] 旧分区是否定期合并
– [ ] 过期数据是否定期清理
– [ ] 分区表监控是否到位
## 性能检查
– [ ] 查询性能是否优化
– [ ] 写入性能是否优化
– [ ] 存储使用是否合理
– [ ] 系统资源使用是否正常
## 维护检查
– [ ] 备份策略是否制定
– [ ] 恢复测试是否执行
– [ ] 文档是否更新
– [ ] 问题是否及时解决
5.3 分表分库常见问题与解决方案
分表分库常见问题与解决方案:
- 数据分布不均匀:重新选择分区键或调整分区策略
- 查询性能下降:优化索引、调整分区策略或增加分区数量
- 管理复杂度高:使用分区管理工具,如pg_partman
- 数据迁移困难:制定详细的数据迁移计划,使用合适的迁移工具
- 事务一致性问题:使用分布式事务或调整业务逻辑
- 备份恢复复杂:制定专门的备份恢复策略
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
