SQL执行计划与优化详解

一、什么是SQL执行计划

执行计划是数据库优化器生成的、用于执行SQL查询的详细步骤说明。它描述了:

  • 如何访问数据(全表扫描、索引扫描等)
  • 表的连接顺序和方式
  • 操作执行的顺序

二、如何查看执行计划

1. MySQL

sql 复制代码
-- 基本执行计划
EXPLAIN SELECT * FROM users WHERE age > 25;

-- 详细执行计划(MySQL 8.0+)
EXPLAIN ANALYZE SELECT * FROM users WHERE age > 25;

-- JSON格式查看
EXPLAIN FORMAT=JSON SELECT * FROM users;

2. PostgreSQL

sql 复制代码
-- 基本计划
EXPLAIN SELECT * FROM users WHERE age > 25;

-- 带实际执行时间
EXPLAIN ANALYZE SELECT * FROM users WHERE age > 25;

-- 带统计信息
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM users;

3. Oracle

sql 复制代码
-- 生成执行计划
EXPLAIN PLAN FOR 
SELECT * FROM users WHERE age > 25;

-- 查看执行计划
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

4. SQL Server

sql 复制代码
-- 文本格式
SET SHOWPLAN_TEXT ON;
GO
SELECT * FROM users WHERE age > 25;
GO
SET SHOWPLAN_TEXT OFF;

-- 图形化(SSMS中)
-- 点击"显示估计的执行计划"按钮或Ctrl+L

三、执行计划关键元素解读

1. 访问方法(Access Methods)

复制代码
- Seq Scan/Full Table Scan: 全表扫描
- Index Scan: 索引扫描
- Index Only Scan: 仅索引扫描
- Bitmap Index Scan: 位图索引扫描
- Hash Scan: 哈希扫描

2. 连接类型(Join Types)

复制代码
- Nested Loop Join: 嵌套循环连接
- Hash Join: 哈希连接
- Merge Join: 合并连接

3. 关键指标

复制代码
- cost: 预估成本(越低越好)
- rows: 预估返回行数
- width: 预估行宽度
- actual time: 实际执行时间
- loops: 循环次数

四、执行计划优化实战

示例分析:识别问题

sql 复制代码
-- 问题查询
EXPLAIN ANALYZE
SELECT u.name, o.order_date, p.product_name
FROM users u
JOIN orders o ON u.id = o.user_id
JOIN products p ON o.product_id = p.id
WHERE u.city = '北京'
AND o.order_date >= '2024-01-01'
ORDER BY o.order_date DESC
LIMIT 100;

优化步骤:

1. 识别全表扫描
sql 复制代码
-- 检查是否缺少索引
EXPLAIN SELECT * FROM users WHERE city = '北京';
-- 如果显示"Seq Scan",考虑创建索引
CREATE INDEX idx_users_city ON users(city);
2. 优化连接顺序
sql 复制代码
-- 查看连接顺序是否合理
-- 小表驱动大表更高效
-- 使用子查询优化
SELECT * FROM (
  SELECT * FROM orders 
  WHERE order_date >= '2024-01-01'
) o
JOIN users u ON o.user_id = u.id
WHERE u.city = '北京';
3. 索引优化组合
sql 复制代码
-- 复合索引(最左前缀原则)
CREATE INDEX idx_orders_user_date ON orders(user_id, order_date DESC);

-- 覆盖索引(包含查询所有列)
CREATE INDEX idx_users_city_name ON users(city) INCLUDE (name);

-- 函数索引
CREATE INDEX idx_lower_email ON users(LOWER(email));
4. 统计信息更新
sql 复制代码
-- 确保统计信息准确
ANALYZE users;  -- PostgreSQL
ANALYZE TABLE users;  -- MySQL
EXEC sp_updatestats;  -- SQL Server

五、常见优化模式

模式1:N+1查询问题

sql 复制代码
-- 反模式:多次查询
SELECT * FROM users WHERE city = '北京';
-- 对每个user执行:
SELECT * FROM orders WHERE user_id = ?;

-- 优化:使用JOIN
SELECT u.*, o.* 
FROM users u 
LEFT JOIN orders o ON u.id = o.user_id 
WHERE u.city = '北京';

模式2:分页优化

sql 复制代码
-- 低效的分页(OFFSET越大越慢)
SELECT * FROM orders ORDER BY id LIMIT 10 OFFSET 1000000;

-- 优化:使用seek方法
SELECT * FROM orders 
WHERE id > last_seen_id 
ORDER BY id 
LIMIT 10;

模式3:避免SELECT *

sql 复制代码
-- 不推荐
SELECT * FROM users WHERE age > 25;

-- 推荐:只选择需要的列
SELECT id, name, email FROM users WHERE age > 25;

六、优化工具和技巧

1. 数据库内置工具

sql 复制代码
-- PostgreSQL: 检查索引使用情况
SELECT * FROM pg_stat_user_indexes;

-- MySQL: 查看索引统计
SHOW INDEX FROM users;

-- MySQL: 性能分析
SET profiling = 1;
SELECT ...;
SHOW PROFILES;
SHOW PROFILE FOR QUERY 1;

2. 查询重写技巧

sql 复制代码
-- OR优化
SELECT * FROM users WHERE age < 20 OR age > 60;
-- 重写为
SELECT * FROM users WHERE age < 20
UNION
SELECT * FROM users WHERE age > 60;

-- IN优化
SELECT * FROM users WHERE id IN (SELECT user_id FROM orders);
-- 重写为
SELECT u.* FROM users u 
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);

3. 配置优化

sql 复制代码
-- 调整内存设置
-- PostgreSQL: work_mem, shared_buffers
-- MySQL: innodb_buffer_pool_size, sort_buffer_size

-- 启用并行查询
-- PostgreSQL: max_parallel_workers_per_gather
-- MySQL 8.0+: optimizer_switch='parallel_query=on'

七、执行计划可视化工具

  1. pgAdmin / DBeaver:内置可视化执行计划
  2. Explain.dalibo.com:PostgreSQL执行计划可视化
  3. MySQL Workbench:Visual Explain功能
  4. Oracle SQL Developer:执行计划图形化

最佳实践总结

  1. 先看执行计划再优化:不要盲目添加索引

  2. 关注高成本操作:全表扫描、排序、临时表

  3. 索引设计原则

    • 为WHERE、JOIN、ORDER BY列创建索引
    • 使用复合索引减少索引数量
    • 避免过度索引影响写入性能
  4. 定期分析

    sql 复制代码
    -- 找出最慢的查询
    SELECT query, total_time 
    FROM pg_stat_statements 
    ORDER BY total_time DESC 
    LIMIT 10;
  5. 测试验证:在生产环境优化前,先在测试环境验证

相关推荐
童谣111 小时前
越华环保集团市级统筹申报数字化中台:政策校验与减排仿真一体化架构
数据库·架构
制造数据与AI践行者老蒋11 小时前
离谱!PromptTemplate 遇上 JSON,花括号直接引发解析战争
数据库·microsoft·json
中微极客11 小时前
用LangChain 0.3构建生产级RAG与Agent:从API集成到Streamlit部署
数据库·人工智能·langchain
吴声子夜歌11 小时前
MongoDB 4.x——并发优化
数据库·mongodb
不如语冰12 小时前
AI大模型入门-Python进阶-上下文管理与with语句
开发语言·数据结构·数据库·人工智能·pytorch·redis·python
提笔了无痕13 小时前
MySQL SQL 从 EXPLAIN 到索引优化,搞懂 SQL 为什么慢
android·sql·mysql
l1t14 小时前
DeepSeek总结的DuckLake 架构深度剖析-2
数据库·架构
YOU OU14 小时前
Redis事务
数据库·redis·缓存
辰同学ovo14 小时前
从一条 SQL 到三个原则:MySQL 心智模型
sql·mysql·adb
数智化管理手记15 小时前
财务大数据怎么管住资金风险?财务大数据和财务数智化到底怎么结合?
大数据·网络·数据库·人工智能·数据挖掘