DatabaseQueryOptimization database-query-optimization

通过索引、高效查询和执行计划分析提高数据库查询性能,减少响应时间和数据库负载。

数据工程 0 次安装 0 次浏览 更新于 3/3/2026

数据库查询优化

概览

慢速数据库查询是常见的性能瓶颈。通过索引、高效查询和执行计划分析进行优化,可以显著提高应用程序性能。

何时使用

  • 响应时间慢
  • 数据库CPU使用率高
  • 性能回归
  • 新功能部署
  • 定期维护

指令

1. 查询分析

-- 分析查询性能

EXPLAIN ANALYZE
SELECT users.id, users.name, COUNT(orders.id) as order_count
FROM users
LEFT JOIN orders ON users.id = orders.user_id
WHERE users.created_at > '2024-01-01'
GROUP BY users.id, users.name
ORDER BY order_count DESC;

-- 结果显示:
-- - 顺序扫描(慢)与索引扫描(快)
-- - 行数:实际与计划(高方差=不好)
-- - 执行时间(毫秒)

-- 关键指标:
-- - 顺序扫描:全表读取(慢)
-- - 索引扫描:使用索引(快)
-- - 嵌套循环:带有循环的连接
-- - 排序:内存或磁盘排序

2. 索引策略

索引类型:

单列:
  CREATE INDEX idx_users_email ON users(email);
  使用:WHERE email = ?
  大小:小,快速创建

复合索引:
  CREATE INDEX idx_orders_user_date
    ON orders(user_id, created_at);
  使用:WHERE user_id = ? AND created_at > ?
  顺序:选择性最大的在前

覆盖索引:
  CREATE INDEX idx_orders_covering
    ON orders(user_id) INCLUDE (total_amount);
  好处:不需要表查找

部分索引:
  CREATE INDEX idx_active_users
    ON users(id) WHERE status = 'active';
  好处:更小,更快

全文索引:
  CREATE FULLTEXT INDEX idx_search
    ON articles(title, content);
  使用:文本搜索查询

---

索引规则:

- 为WHERE条件创建索引
- 为JOIN列创建索引
- 为ORDER BY创建索引
- 不要过度索引(减慢写入)
- 监控索引使用情况
- 移除未使用的索引
- 定期更新统计信息
- 为过滤查询创建部分索引

缺失索引查询:
SELECT object_name, equality_columns
FROM sys.dm_db_missing_index_details
ORDER BY equality_columns;

3. 查询优化技术

# 常见优化模式

# 之前(N+1查询)
for user in users:
    orders = db.query("SELECT * FROM orders WHERE user_id = ?", user.id)
    # 1 + N查询

# 之后(单查询与JOIN)
orders = db.query("""
  SELECT u.*, o.* FROM users u
  LEFT JOIN orders o ON u.id = o.user_id
  WHERE u.created_at > ?
""", date_threshold)

# 之前(低效WHERE)
SELECT * FROM users
WHERE LOWER(email) = LOWER('Test@Example.com')
# 不能使用索引(使用了函数)

# 之后(索引友好)
SELECT * FROM users
WHERE email = 'test@example.com'
# 案例不敏感约束+索引

# 之前(通配符在开始)
SELECT * FROM users WHERE email LIKE '%example.com'
# 不能使用索引(通配符在开始)

# 之后(通配符在结束)
SELECT * FROM users WHERE email LIKE 'user%'
# 可以使用索引

# 之前(慢速聚合)
SELECT user_id, COUNT(*) as cnt
FROM orders
GROUP BY user_id
ORDER BY cnt DESC
LIMIT 10

# 之后(预聚合)
SELECT user_id, order_count
FROM user_order_stats
WHERE order_count IS NOT NULL
ORDER BY order_count DESC
LIMIT 10

4. 优化清单

分析:
  [ ] 运行EXPLAIN ANALYZE在慢查询上
  [ ] 检查实际与估计行数
  [ ] 查找顺序扫描
  [ ] 识别昂贵操作
  [ ] 比较执行计划

索引:
  [ ] 索引WHERE列
  [ ] 索引JOIN列
  [ ] 索引ORDER BY列
  [ ] 检查未使用索引
  [ ] 移除重复索引
  [ ] 策略性创建复合索引
  [ ] 分析索引统计信息

查询优化:
  [ ] 移除不必要的列(SELECT *)
  [ ] 使用JOIN代替子查询
  [ ] 避免WHERE中使用函数
  [ ] 谨慎使用通配符(避免%)
  [ ] 批量操作
  [ ] 使用LIMIT对结果集
  [ ] 归档旧数据

缓存:
  [ ] 实施查询缓存
  [ ] 缓存聚合
  [ ] 使用Redis进行热数据缓存
  [ ] 策略性失效

监控:
  [ ] 跟踪慢查询
  [ ] 监控索引使用情况
  [ ] 设置警报
  [ ] 定期更新统计信息
  [ ] 测量改进

---

预期改进:

通过适当的索引:
  - 顺序扫描 → 索引扫描
  - 响应时间:5秒 → 50ms(100倍速度提升)
  - CPU使用率:80% → 20%
  - 并发用户:100 → 1000

快速胜利:
  - 对频繁过滤的列添加索引
  - 修复N+1查询
  - 对大型结果集使用LIMIT
  - 归档旧数据
  - 预期:20-50%的改进

关键点

  • EXPLAIN ANALYZE显示查询执行
  • 索引必须匹配WHERE/JOIN/ORDER BY
  • 避免WHERE子句中的函数
  • 修复N+1查询(连接代替循环)
  • 定期监控慢查询日志
  • 需要更新统计信息以确保准确性
  • 预先计算聚合
  • 归档历史数据
  • 使用explain计划前后
  • 持续测量和监控