PostgreSQL从入门到进阶
🏠 首页
  • 开始学习

    • PostgreSQL介绍
    • 安装配置
  • 基础教程

    • 数据库与表
    • 数据类型
    • CRUD操作
    • WHERE条件
  • 进阶查询

    • 联表查询
    • 聚合函数
    • 子查询
    • 视图
  • 性能优化

    • 索引优化
    • 查询优化
    • EXPLAIN分析
  • 事务处理
  • 触发器
  • 存储过程
  • JSON数据
  • 博客系统
  • 用户管理系统
  • 最佳实践
🔗 编程指南
🏠 首页
  • 开始学习

    • PostgreSQL介绍
    • 安装配置
  • 基础教程

    • 数据库与表
    • 数据类型
    • CRUD操作
    • WHERE条件
  • 进阶查询

    • 联表查询
    • 聚合函数
    • 子查询
    • 视图
  • 性能优化

    • 索引优化
    • 查询优化
    • EXPLAIN分析
  • 事务处理
  • 触发器
  • 存储过程
  • JSON数据
  • 博客系统
  • 用户管理系统
  • 最佳实践
🔗 编程指南
  • 开始之前

    • 教程介绍
    • 什么是PostgreSQL?
    • 安装PostgreSQL
  • 基础入门

    • 数据库和表的概念
    • 数据类型详解
    • 增删改查操作(CRUD)
    • 查询条件WHERE
  • 进阶查询

    • 多表联查JOIN
    • 聚合函数
    • 子查询
    • 视图VIEW
  • 性能优化

    • 索引详解
    • 查询优化
    • 执行计划分析
  • 高级特性

    • 事务处理
    • 触发器
    • 存储过程
    • JSON数据
  • 实战项目

    • 实战项目:博客系统
    • 实战项目:用户管理系统
    • 最佳实践

查询优化

我是长安!今天教你写出快如闪电的SQL!⚡

🎯 查询优化的重要性

同样的功能,好的SQL和差的SQL性能可能相差100倍!

-- ❌ 慢查询(10秒)
SELECT * FROM orders WHERE YEAR(created_at) = 2023;

-- ✅ 快查询(0.1秒)
SELECT * FROM orders 
WHERE created_at >= '2023-01-01' AND created_at < '2024-01-01';

📝 优化原则

1. 只查询需要的列

-- ❌ 不好
SELECT * FROM users;

-- ✅ 好
SELECT id, username, email FROM users;

2. 避免SELECT DISTINCT

-- ❌ 慢
SELECT DISTINCT category FROM products;

-- ✅ 快
SELECT category FROM products GROUP BY category;

3. 使用LIMIT

-- ❌ 查询所有
SELECT * FROM posts ORDER BY created_at DESC;

-- ✅ 只要前10条
SELECT * FROM posts ORDER BY created_at DESC LIMIT 10;

4. 避免在WHERE中使用函数

-- ❌ 索引失效
SELECT * FROM users WHERE UPPER(username) = 'ADMIN';

-- ✅ 使用表达式索引或改写查询
SELECT * FROM users WHERE username = 'admin';

5. 使用EXISTS代替IN

-- ❌ 子查询结果很大时很慢
SELECT * FROM users 
WHERE id IN (SELECT user_id FROM orders);

-- ✅ 更快
SELECT * FROM users u
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);

6. 避免N+1查询

-- ❌ N+1问题(在应用层)
-- 1. 查询所有文章
SELECT * FROM posts;
-- 2. 循环查询每个作者(执行N次)
SELECT * FROM users WHERE id = ?;

-- ✅ 使用JOIN一次查出
SELECT p.*, u.username 
FROM posts p 
JOIN users u ON p.user_id = u.id;

7. 批量操作

-- ❌ 循环插入
INSERT INTO logs VALUES (1, 'log1');
INSERT INTO logs VALUES (2, 'log2');
-- ... 1000次

-- ✅ 批量插入
INSERT INTO logs VALUES 
    (1, 'log1'),
    (2, 'log2'),
    -- ...
    (1000, 'log1000');

🎯 JOIN优化

-- 小表在前,大表在后
SELECT * FROM small_table
JOIN large_table ON small_table.id = large_table.ref_id;

-- 在JOIN列上创建索引
CREATE INDEX idx_large_table_ref_id ON large_table(ref_id);

-- 减少JOIN的表数量
-- 如果不需要某个表的数据,就不要JOIN

📊 分页优化

-- ❌ 深分页很慢
SELECT * FROM posts 
ORDER BY id 
OFFSET 100000 LIMIT 10;  -- 需要跳过10万行

-- ✅ 使用WHERE代替OFFSET
SELECT * FROM posts 
WHERE id > 100000 
ORDER BY id 
LIMIT 10;

-- ✅ 或者记录上次的位置
SELECT * FROM posts 
WHERE id > :last_id 
ORDER BY id 
LIMIT 10;

💡 COUNT优化

-- ❌ COUNT(*)在大表上很慢
SELECT COUNT(*) FROM large_table;

-- ✅ 使用估算(适合不需要精确值的场景)
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE relname = 'large_table';

-- ✅ 或者维护计数器表
CREATE TABLE counters (
    table_name VARCHAR(50),
    count BIGINT
);

📚 下一步

继续学习执行计划分析!


长安的话:性能优化是个持续的过程,多实践多总结!💪

最近更新: 2025/12/1 18:21
Prev
索引详解
Next
执行计划分析