2. 慢查询定义:数据库慢查询的判定标准
在压测与生产环境中,慢查询是导致连接池耗尽与系统雪崩的核心诱因。要精准识别慢查询,不能仅凭单一指标,而需从执行时间、扫描行数与索引使用情况三个维度综合判定。以下逐一展开。
2.1 执行时间:最直观的阈值
数据库通过 long_query_time 参数定义“慢”的时间门槛。MySQL 默认值为 10 秒,但在高并发微服务架构中,通常建议调低至 1 秒甚至 100 毫秒。
| 场景 | 推荐 long_query_time | 说明 |
|---|---|---|
| OLTP 在线交易 | 100ms – 500ms | 用户交互敏感,超过 500ms 即影响体验 |
| 内部报表/批处理 | 1s – 5s | 容忍度较高,但需避免阻塞连接池 |
| 默认 MySQL 配置 | 10s | 仅适合离线环境,生产必须调低 |
压测建议:在压测脚本中,将
long_query_time 临时设为 0,可记录所有查询的完整执行时间分布,便于识别“亚健康”查询。
2.2 扫描行数:代价的量化指标
执行时间受硬件、并发、缓存影响,波动较大。而扫描行数(Rows_examined)是更稳定的代价度量。MySQL 慢查询日志中会记录该值。
- 全表扫描:扫描行数 ≈ 表总行数,通常意味着索引缺失或查询条件无法下推。
- 索引扫描:扫描行数远小于表总行数,但仍可能因回表或范围过大而变慢。
- 理想状态:扫描行数 ≈ 返回行数(
Rows_sent),即“精准命中”。
判定经验:当
Rows_examined / Rows_sent > 1000 时,该查询大概率存在索引问题,应纳入慢查询优化清单。
2.3 索引使用情况:执行计划的核心证据
通过 EXPLAIN 分析查询计划,重点关注以下字段:
| EXPLAIN 字段 | 慢查询信号 | 说明 |
|---|---|---|
type |
ALL(全表扫描) |
最差情况,必须避免 |
type |
index(全索引扫描) |
仍可能慢,尤其索引列宽时 |
type |
range / ref |
可接受,但需关注扫描范围 |
type |
eq_ref / const |
最优,单行或少量行匹配 |
Extra |
Using filesort |
排序未用索引,额外开销 |
Extra |
Using temporary |
使用临时表,通常伴随 GROUP BY 或 DISTINCT 问题 |
key_len |
过短或过长 | 过短可能未用联合索引全部列;过长则索引冗余 |
常见误区:并非所有使用索引的查询都是快查询。例如
SELECT * FROM orders WHERE status=1 ORDER BY create_time,即使 status 有索引,若满足条件行数过多,回表 + 排序仍可能成为慢查询。
2.4 综合判定流程
在实际压测与运维中,建议按以下步骤判定一条查询是否为“需要治理的慢查询”:
- 阈值初筛:执行时间 >
long_query_time,进入慢查询日志。 - 扫描行数评估:
Rows_examined是否超过表行数的 10%?若是,标记为高代价查询。 - 执行计划检查:
type是否为ALL或index?Extra是否包含Using filesort或Using temporary? - 综合评级:满足任意两项,即判定为“高风险慢查询”,需优先优化。
2.5 压测中的慢查询判定实践
在压测场景下,慢查询的判定需要结合实时监控与事后分析:
- 实时监控:通过
SHOW PROCESSLIST或performance_schema观察长时间未完成的查询,重点关注State为Sending data、Creating sort index的会话。 - 事后分析:开启慢查询日志(
slow_query_log=ON),并设置log_queries_not_using_indexes=ON,可捕获所有未使用索引的查询,无论其执行时间长短。 - 连接池视角:当慢查询堆积时,连接池中的连接被长时间占用,导致
active连接数飙升,idle连接数归零,最终触发连接池耗尽。
核心结论:慢查询的判定不是终点,而是连接池治理与熔断降级策略的起点。只有将执行时间、扫描行数、索引使用情况三者结合,才能准确识别出真正威胁系统稳定性的“危险查询”。