码农之家

专注优质代码开发,为软件行业发展贡献力量

PostgreSQL:简单的实践

1. 合理设计数据库结构

  • 规范化设计:避免数据冗余,至少达到第三范式(3NF),减少更新异常
  • 选择合适的数据类型:例如用int而非varchar存储数字,用date/timestamp存储日期
  • 添加适当的约束:使用主键、外键、唯一约束、非空约束保证数据完整性

示例:创建表时添加适当约束

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(100) NOT NULL UNIQUE,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);


2. 优化索引使用

  • 只为常用查询字段建索引:过度索引会降低写入性能
  • 为外键自动创建索引:PostgreSQL不会自动为外键建索引
  • 考虑复合索引:对于多字段查询,复合索引可能比单个字段索引更有效
  • 定期维护索引:使用REINDEX修复碎片化索引

示例:为外键创建索引

CREATE INDEX idx_orders_user_id ON orders(user_id);


示例:创建复合索引

CREATE INDEX idx_orders_date_status ON orders(order_date, status);


3. 查询优化

  • 使用EXPLAIN分析查询计划:识别慢查询的瓶颈
  • 避免SELECT * :只查询需要的字段,减少数据传输
  • 合理使用JOIN而非子查询:某些情况下JOIN性能更好
  • 限制返回行数:使用LIMIT避免返回过多数据

示例:分析查询执行计划

EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 123 AND status = 'active';


4. 定期备份

  • 使用pg_dump进行逻辑备份:适合小到中型数据库
  • 考虑pg_basebackup进行物理备份:适合大型数据库
  • 定期测试恢复流程:确保备份可用
  • 设置自动备份计划:避免人为疏忽

示例:备份整个数据库

命令行:pg_dump -U username -d dbname -F c -f backup_filename.dump


示例:恢复数据库

命令行:pg_restore -U username -d dbname backup_filename.dump


5. 实践

示例:创建具有有限权限的用户

CREATE USER app_user WITH PASSWORD 'strong_password';
GRANT SELECT, INSERT, UPDATE ON TABLE users TO app_user;


6. 性能优化

  • 根据服务器配置调整postgresql.conf:关键参数包括shared_buffers、work_mem、maintenance_work_mem等
  • 监控数据库性能:使用pg_stat_statements扩展跟踪慢查询
  • 定期VACUUM:清理删除/更新后的死元组(PostgreSQL 12+默认启用自动清理)


示例:启用pg_stat_statements扩展

CREATE EXTENSION pg_stat_statements;


示例:查看最耗时的查询

SELECT queryid, query, total_time FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10;


7. 应用

  • 使用连接池:如pgBouncer,避免频繁创建/关闭连接
  • 使用事务:确保数据操作的原子性
  • 批量操作代替循环单条操作:提高写入效率

示例:批量插入

INSERT INTO logs (message, created_at) VALUES
('msg1', NOW()),
('msg2', NOW()),
('msg3', NOW());


根据具体应用场景,可能还需要进一步的针对性优化。

什么是数据库的第三范式?3NF

第三范式(3NF,Third Normal Form)是数据库设计中规范化的重要准则,用于减少数据冗余和避免更新异常(插入、删除、修改时出现的数据不一致问题)。

它建立在第一范式(1NF)和第二范式(2NF)的基础上,定义如下:

第三范式(3NF)的核心要求:

(1)必须满足第二范式(2NF)

即表中所有非主属性完全依赖于主键(不能存在部分依赖)。

(2)消除传递依赖

表中的非主属性不能依赖于其他非主属性(即不存在"非主属性A → 非主属性B"的依赖关系)。

通俗理解:

一张表只应描述一个实体(如"学生"表只描述学生信息,"课程"表只描述课程信息)。

表中的所有字段(列)都应直接依赖于主键,而不是通过其他字段间接依赖。


示例:不符合3NF的情况

假设有一张 学生成绩表:

学生ID(主键)学生姓名所属班级班主任课程ID成绩
101张三 一班 王老师C0190
102李四一班王老师C0185

问题分析:

①"班主任"依赖于"所属班级"(非主属性),而非直接依赖主键"学生ID",存在传递依赖(学生ID → 所属班级 → 班主任)。

②当"一班"的班主任从"王老师"换成"李老师"时,需要更新所有一班学生的记录,容易出错。

符合3NF的设计:

拆分为3张表,消除传递依赖。

(1)学生表(学生ID为主键)

学生ID学生姓名所属班级
101张三一班
102李四一班

(2)班级表(班级名称为主键)

班级名称班主任
一班王老师

(3)成绩表(学生ID+课程ID为主键)

学生ID课程ID成绩
101C0190
102C0185

所有非主属性都直接依赖于各自表的主键,不存在传递依赖,符合3NF。

3NF的作用:

  • 减少数据冗余(如"班主任"只在班级表中存储一次)。
  • 提高数据一致性(修改班主任时只需改一处)。
  • 简化维护(避免重复数据的多次更新)。

实际设计中,3NF是多数场景的"黄金标准",保证了规范化,也不过度拆分导致查询复杂。


luodong

0 评论数