4. 数据库查询优化:索引设计与调优、慢查询分析与解决、连接池配置实战
数据库查询优化,说白了就是让数据库少干活、快干活。我见过太多系统,业务逻辑写得挺漂亮,结果一到数据库层面就卡死了。今天咱们就聊聊索引、慢查询和连接池这三个核心点。
4.1 索引设计:不是越多越好
很多人觉得索引就是加速查询的,那就多建几个呗。错。索引是空间换时间,写操作会变慢。我有个项目,上线后发现写入性能极差,一查,一张表建了12个索引。你说能不慢吗?
4.1.1 索引类型与选择
| 索引类型 | 适用场景 | 注意事项 |
|---|---|---|
| B+Tree 索引 | 范围查询、排序、分组 | 最左前缀原则 |
| Hash 索引 | 等值查询 | 不支持范围查询 |
| 全文索引 | 文本搜索 | MyISAM/InnoDB 都支持 |
| 空间索引 | 地理坐标查询 | MyISAM 专用 |
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 单独查询。那索引基本废了。后来我调整了顺序,把区分度高的字段放前面。
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 要优化 |
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 |
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 秒,把连接池全占满了,其他请求全在排队。
4.4 知识体系总览
下面这张图把本章的核心内容串起来了。你可以对照着梳理自己的优化思路。
4.5 总结
数据库查询优化没有银弹。索引、慢查询、连接池,这三块是基本功。我建议你从慢查询日志入手,找到最慢的 SQL,用 EXPLAIN 分析,然后针对性加索引或改写 SQL。连接池配置先按推荐值来,再根据压测结果微调。
嗯,今天就聊到这儿。记住一点:优化是持续的过程,不是一次性的活儿。