4. 数据库查询优化:索引设计与调优、慢查询分析与解决、连接池配置实战

数据库查询优化,说白了就是让数据库少干活、快干活。我见过太多系统,业务逻辑写得挺漂亮,结果一到数据库层面就卡死了。今天咱们就聊聊索引、慢查询和连接池这三个核心点。

4.1 索引设计:不是越多越好

很多人觉得索引就是加速查询的,那就多建几个呗。错。索引是空间换时间,写操作会变慢。我有个项目,上线后发现写入性能极差,一查,一张表建了12个索引。你说能不慢吗?

4.1.1 索引类型与选择

索引类型 适用场景 注意事项
B+Tree 索引 范围查询、排序、分组 最左前缀原则
Hash 索引 等值查询 不支持范围查询
全文索引 文本搜索 MyISAM/InnoDB 都支持
空间索引 地理坐标查询 MyISAM 专用
我的习惯: 优先用 B+Tree 索引。InnoDB 默认就是它,支持范围查询和排序,日常够用了。

4.1.2 联合索引设计原则

联合索引有个核心原则:最左前缀。比如你建了 (a, b, c) 索引,那查询条件必须从 a 开始才能用到索引。

-- 能用到索引
SELECT * FROM t WHERE a = 1 AND b = 2;
SELECT * FROM t WHERE a = 1 ORDER BY b;

-- 用不到索引
SELECT * FROM t WHERE b = 2;
SELECT * FROM t WHERE c = 3;

我曾经踩过一个坑:给订单表建了 (user_id, status, create_time) 索引,结果业务方经常按 status 单独查询。那索引基本废了。后来我调整了顺序,把区分度高的字段放前面。

避坑指南: 索引不是越多越好。一张表建议控制在 5 个以内。写频繁的表更要谨慎。

4.2 慢查询分析与解决

慢查询是性能问题的直接表现。我一般先开慢查询日志,看看哪些 SQL 在拖后腿。

4.2.1 开启慢查询日志

-- 查看当前配置
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

-- 设置慢查询阈值(单位:秒)
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log = ON;

我习惯把阈值设成 1 秒。线上业务如果超过 1 秒,基本就是有问题了。

4.2.2 使用 EXPLAIN 分析执行计划

拿到慢 SQL 后,用 EXPLAIN 看看它怎么执行的。

EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND status = 'PAID';
字段 含义 重点关注
type 访问类型 ALL 全表扫描要避免
key 使用的索引 NULL 表示没用到索引
rows 扫描行数 越小越好
Extra 额外信息 Using filesort 要优化
核心指标: type 字段从好到差依次是:system > const > eq_ref > ref > range > index > ALL。看到 ALL 就要警惕了。

4.2.3 常见慢查询场景与优化

  • 全表扫描: 加索引或改写 SQL
  • 索引失效: 检查函数操作、隐式类型转换
  • 排序慢: 排序字段加索引
  • 分页深: 用游标分页代替 offset

举个例子,分页查询 LIMIT 100000, 20 会扫描 100020 行。我一般改成 WHERE id > 100000 LIMIT 20,效率提升明显。

4.3 连接池配置实战

连接池是数据库访问的缓冲层。配置不好,系统照样崩。

4.3.1 连接池核心参数

参数 说明 建议值
maximumPoolSize 最大连接数 CPU 核心数 × 2 + 1
minimumIdle 最小空闲连接 最大连接数的 10%-20%
connectionTimeout 连接超时 30000ms
idleTimeout 空闲超时 600000ms
maxLifetime 连接最大存活时间 1800000ms
我的经验: 连接数不是越大越好。太多连接反而会增加数据库上下文切换的开销。我一般从 10 开始压测,逐步往上调。

4.3.2 HikariCP 配置示例

spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
      pool-name: MyPool

HikariCP 是目前最快的连接池。我所有新项目都用它。

4.3.3 连接池监控

连接池用久了,难免出问题。我一般会监控这几个指标:

  • 活跃连接数:是否接近上限
  • 等待获取连接的线程数:是否持续增长
  • 连接超时次数:是否频繁

如果发现连接池满了,先看是不是有慢查询占着连接不放。我曾经遇到过,一个慢查询跑了 30 秒,把连接池全占满了,其他请求全在排队。

避坑指南: 连接泄漏是常见问题。用完的连接一定要关闭。建议用 try-with-resources 或框架的自动管理。

4.4 知识体系总览

下面这张图把本章的核心内容串起来了。你可以对照着梳理自己的优化思路。

数据库查询优化知识体系 数据库查询优化 索引设计与调优 慢查询分析与解决 连接池配置实战 B+Tree / Hash 联合索引原则 EXPLAIN 分析 慢查询日志 参数配置 监控与调优 核心原则:索引减少扫描行数,慢查询定位问题,连接池控制并发 三者配合才能构建高性能数据库访问层

4.5 总结

数据库查询优化没有银弹。索引、慢查询、连接池,这三块是基本功。我建议你从慢查询日志入手,找到最慢的 SQL,用 EXPLAIN 分析,然后针对性加索引或改写 SQL。连接池配置先按推荐值来,再根据压测结果微调。

嗯,今天就聊到这儿。记住一点:优化是持续的过程,不是一次性的活儿。