Jorgen's blog Jorgen's blog
首页
  • 平台架构
  • 混合式开发记录
  • 推送服务
  • 数据分析
  • 实时调度
  • 架构思想

    • 分布式
  • 编程框架工具

    • 编程语言
    • 框架
    • 开发工具
  • 数据存储与处理

    • 数据库
    • 大数据
  • 消息、缓存与搜索

    • 消息队列
    • 搜索与日志分析
  • 前端与跨端开发

    • 前端技术
    • Android
  • 系统与运维

    • 操作系统
    • 容器化与 DevOps
  • 物联网与安全

    • 通信协议
    • 安全
    • 云平台
newland
  • 关于我
  • 终身学习
  • 关于时间的感悟
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

jorgen

Love it, make mistakes, learn, keep grinding.
首页
  • 平台架构
  • 混合式开发记录
  • 推送服务
  • 数据分析
  • 实时调度
  • 架构思想

    • 分布式
  • 编程框架工具

    • 编程语言
    • 框架
    • 开发工具
  • 数据存储与处理

    • 数据库
    • 大数据
  • 消息、缓存与搜索

    • 消息队列
    • 搜索与日志分析
  • 前端与跨端开发

    • 前端技术
    • Android
  • 系统与运维

    • 操作系统
    • 容器化与 DevOps
  • 物联网与安全

    • 通信协议
    • 安全
    • 云平台
newland
  • 关于我
  • 终身学习
  • 关于时间的感悟
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 时序数据库
  • Postgres
  • MongoDB入门与实践
  • NewSQL数据库:关系型与NoSQL的完美结合
  • Redis入门与实践:高性能键值数据库指南
  • Redis入门与实践
  • SQL基础:关系型数据库的语言
  • 关系型数据库基础
  • 关系型数据库基础与SQL入门
  • 关系型数据库基础理论
  • 关系数据库设计与SQL基础
  • 数据库分类与选型指南
  • 数据库性能优化与调优实战指南
  • 数据库索引与性能优化
  • 数据库索引原理与优化
  • 数据库设计与数据建模:从概念到实践
  • 数据库事务与并发控制:保证数据一致性的核心技术
  • 数据库事务与并发控制:保证数据一致性的核心机制
  • 数据库安全与权限管理-保护数据的基石
  • 数据库备份与恢复策略-确保数据安全的最后一道防线
  • 数据库分布式架构:从CAP理论到分片策略的全面解析
  • 数据库监控与运维-确保数据库健康运行的守护者
  • 数据库高可用方案-构建永不掉线的数据库架构
  • 数据库连接池技术:提升应用性能的关键组件
  • 数据库查询优化与执行计划分析-提升SQL性能的关键技术
    • 前言
    • 执行计划基础
      • 什么是执行计划?
      • 如何获取执行计划
    • 执行计划的关键指标
      • 1. 访问路径(Access Path)
      • 2. 连接类型(Join Type)
      • 3. 成本估算(Cost Estimation)
    • 常见性能问题及优化策略
      • 问题1:全表扫描
      • 问题2:索引失效
      • 问题3:连接顺序不当
    • 高级执行计划分析技巧
      • 1. 使用EXPLAIN ANALYZE
      • 2. 检查预估与实际的差异
      • 3. 分析并行查询执行
    • 实战案例:优化复杂报表查询
      • 问题场景
      • 分析执行计划
      • 优化方案
      • 优化结果
    • 结语
  • 数据库迁移策略:平滑过渡的关键步骤与技术实现
  • 数据库缓存策略:提升系统性能的关键武器
  • 数据库性能问题诊断与排查-从现象到根源的系统化方法
  • 数据库版本管理与演进-构建平滑升级的技术路径
  • 数据库分片与分布式数据管理-构建可扩展数据架构的核心技术
  • 数据库云服务与托管解决方案-构建现代化数据架构的必经之路
  • database
Jorgen
2026-01-28
目录

数据库查询优化与执行计划分析-提升SQL性能的关键技术

# 前言

作为一名经常与数据库打交道的开发者,我经常遇到这样的场景:明明加了索引,查询还是慢得像蜗牛爬行。🐌 这时候,如果我们能够深入理解数据库的执行计划,就能像侦探一样,找出SQL性能问题的真正"凶手"。

提示

执行计划是数据库引擎执行查询的详细路线图,理解它就像是拥有了数据库的"内部说明书"。

在本文中,我将分享如何分析数据库执行计划,以及如何基于执行计划进行有效的查询优化。无论你是开发人员还是DBA,这些技巧都能帮你解决那些令人头疼的性能问题。

# 执行计划基础

# 什么是执行计划?

执行计划(Execution Plan)是数据库引擎解析、优化和执行SQL查询的具体步骤的描述。它告诉我们数据库将如何执行我们的查询,包括:

  • 表的访问方式(全表扫描、索引扫描等)
  • 连接操作的方式(嵌套循环、哈希连接、合并连接等)
  • 排序和分组操作
  • 使用的索引
  • 预估的行数和成本

# 如何获取执行计划

不同数据库系统获取执行计划的方式略有不同:

MySQL/MariaDB:

EXPLAIN SELECT * FROM users WHERE age > 30;
1

PostgreSQL:

EXPLAIN ANALYZE SELECT * FROM users WHERE age > 30;
1

Oracle:

EXPLAIN PLAN FOR SELECT * FROM users WHERE age > 30;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
1
2

SQL Server:

SET SHOWPLAN_TEXT ON;
GO
SELECT * FROM users WHERE age > 30;
GO
1
2
3
4

# 执行计划的关键指标

# 1. 访问路径(Access Path)

执行计划中最关键的部分是表访问路径,常见的访问方式包括:

  • 全表扫描(Table Scan):数据库读取表中的所有行
  • 索引扫描(Index Scan):通过索引查找数据
  • 索引范围扫描(Index Range Scan):查找索引中某个范围内的数据
  • 索引唯一扫描(Index Unique Scan):通过唯一索引查找特定值

THEOREM

全表扫描通常意味着性能问题,特别是对于大型表。理想情况下,查询应该使用合适的索引来避免全表扫描。

# 2. 连接类型(Join Type)

当查询涉及多表连接时,执行计划会显示使用的连接算法:

  • 嵌套循环连接(Nested Loop Join):适合小表驱动大表
  • 哈希连接(Hash Join):适合大数据量的等值连接
  • 合并连接(Merge Join):适合已排序数据的连接

# 3. 成本估算(Cost Estimation)

执行计划通常会显示每个操作的成本估算,成本越低表示数据库认为该执行路径越高效。

# 常见性能问题及优化策略

# 问题1:全表扫描

症状:执行计划显示"ALL"或"Seq Scan"

案例:

-- 低效查询
SELECT * FROM orders WHERE customer_id = 123;
1
2

解决方案:

-- 为customer_id创建索引
CREATE INDEX idx_orders_customer ON orders(customer_id);
1
2

# 问题2:索引失效

症状:明明有索引,但执行计划仍使用全表扫描

常见原因:

  • 在索引列上使用函数
  • 使用了不等于操作符(!=, <>)
  • 使用了OR条件
  • 使用了LIKE '%pattern'(前导通配符)

案例:

-- 索引失效的查询
SELECT * FROM users WHERE name LIKE '%john%';
1
2

解决方案:

-- 重写查询或使用全文索引
SELECT * FROM users WHERE name LIKE 'john%';
1
2

# 问题3:连接顺序不当

症状:复杂多表查询性能差

案例:

-- 低效的多表查询
SELECT o.*, c.*, p.* 
FROM orders o
JOIN customers c ON o.customer_id = c.id
JOIN products p ON o.product_id = p.id
WHERE c.country = 'USA' AND o.status = 'pending';
1
2
3
4
5
6

优化策略:

  1. 确保连接条件有索引
  2. 考虑连接顺序(小表驱动大表)
  3. 对于大数据量,考虑使用临时表或物化视图

# 高级执行计划分析技巧

# 1. 使用EXPLAIN ANALYZE

EXPLAIN ANALYZE不仅显示执行计划,还会实际执行查询并返回实际执行时间和行数,这对于评估计划的真实性能非常有价值。

PostgreSQL示例:

EXPLAIN ANALYZE 
SELECT * FROM orders 
WHERE customer_id = 123 AND order_date > '2023-01-01';
1
2
3

# 2. 检查预估与实际的差异

数据库的优化器基于统计信息预估行数,但预估可能不准确。当预估行数与实际行数差异很大时,可能导致优化器选择错误的执行计划。

解决方法:

  • 定期更新统计信息
  • 考虑使用更精确的统计收集方法
  • 在极端情况下,可以手动设置提示(hints)引导优化器

# 3. 分析并行查询执行

现代数据库支持并行查询,分析并行执行计划可以帮助我们:

  • 确认查询是否使用了并行执行
  • 检查并行度设置是否合理
  • 识别并行执行的瓶颈

PostgreSQL示例:

-- 启用并行执行
SET max_parallel_workers_per_gather = 4;

EXPLAIN ANALYZE 
SELECT COUNT(*) FROM large_table WHERE status = 'active';
1
2
3
4
5

# 实战案例:优化复杂报表查询

# 问题场景

我们需要优化一个复杂的报表查询,该查询涉及多表连接、聚合和排序:

SELECT 
    c.customer_name,
    COUNT(o.id) AS order_count,
    SUM(o.total_amount) AS total_amount,
    COUNT(DISTINCT p.id) AS product_count
FROM customers c
JOIN orders o ON c.id = o.customer_id
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
WHERE c.region = 'North America' 
  AND o.order_date BETWEEN '2023-01-01' AND '2023-12-31'
  AND p.category = 'Electronics'
GROUP BY c.id, c.customer_name
ORDER BY total_amount DESC
LIMIT 10;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 分析执行计划

通过EXPLAIN ANALYZE我们发现:

  1. customers表使用了region索引,效率高
  2. orders表进行了全表扫描
  3. 连接操作使用了嵌套循环,效率低

# 优化方案

  1. 为orders表添加复合索引:
CREATE INDEX idx_orders_customer_date ON orders(customer_id, order_date);
1
  1. 为order_items表添加索引:
CREATE INDEX idx_order_items_product ON order_items(product_id);
1
  1. 重写查询,使用CTE提高可读性:
WITH electronics_orders AS (
    SELECT 
        o.customer_id,
        o.id AS order_id,
        o.total_amount
    FROM orders o
    JOIN order_items oi ON o.id = oi.order_id
    JOIN products p ON oi.product_id = p.id
    WHERE p.category = 'Electronics'
      AND o.order_date BETWEEN '2023-01-01' AND '2023-12-31'
),
customer_stats AS (
    SELECT 
        c.id,
        c.customer_name,
        COUNT(eo.order_id) AS order_count,
        SUM(eo.total_amount) AS total_amount,
        COUNT(DISTINCT oi.product_id) AS product_count
    FROM customers c
    JOIN electronics_orders eo ON c.id = eo.customer_id
    LEFT JOIN order_items oi ON eo.order_id = oi.order_id
    WHERE c.region = 'North America'
    GROUP BY c.id, c.customer_name
)
SELECT * FROM customer_stats
ORDER BY total_amount DESC
LIMIT 10;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 优化结果

优化后的查询执行时间从原来的5秒降低到200毫秒,性能提升了25倍!🚀

# 结语

理解执行计划是数据库性能优制的核心技能。通过分析执行计划,我们可以:

  1. 识别性能瓶颈所在
  2. 验证索引的有效性
  3. 了解数据库的内部工作机制
  4. 制定针对性的优化策略

"不理解的优化,都是瞎折腾。" —— 数据库优化箴言 ::>

在实际工作中,我建议:

  1. 养成分析复杂查询执行计划的习惯
  2. 定期审查慢查询日志中的执行计划
  3. 学习你使用的特定数据库的执行计划格式和指标
  4. 考虑使用专门的性能分析工具(如pgBadger、MySQL Enterprise Monitor等)

记住,数据库优化不是一次性的工作,而是持续的过程。只有深入理解执行计划,我们才能写出真正高效的SQL查询。

"好的SQL不是写出来的,而是分析出来的。" —— Jorgen的数据库心得

#数据库优化#SQL性能#执行计划
上次更新: 2026/01/28, 15:47:20
数据库连接池技术:提升应用性能的关键组件
数据库迁移策略:平滑过渡的关键步骤与技术实现

← 数据库连接池技术:提升应用性能的关键组件 数据库迁移策略:平滑过渡的关键步骤与技术实现→

最近更新
01
LLM
01-30
02
intro
01-30
03
intro
01-30
更多文章>
Theme by Vdoing | Copyright © 2019-2026 Jorgen | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式