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 综合判定流程

在实际压测与运维中,建议按以下步骤判定一条查询是否为“需要治理的慢查询”:

  1. 阈值初筛:执行时间 > long_query_time,进入慢查询日志。
  2. 扫描行数评估:Rows_examined 是否超过表行数的 10%?若是,标记为高代价查询。
  3. 执行计划检查:type 是否为 ALL 或 index?Extra 是否包含 Using filesort 或 Using temporary?
  4. 综合评级:满足任意两项,即判定为“高风险慢查询”,需优先优化。
慢查询三维判定模型 执行时间 long_query_time 阈值 扫描行数 Rows_examined 代价 索引使用情况 EXPLAIN 执行计划 综合判定 满足两项即高风险 标记为慢查询 → 优化 压测时建议将 long_query_time 设为 0,记录所有查询分布

2.5 压测中的慢查询判定实践

在压测场景下,慢查询的判定需要结合实时监控与事后分析:

  • 实时监控:通过 SHOW PROCESSLIST 或 performance_schema 观察长时间未完成的查询,重点关注 State 为 Sending data、Creating sort index 的会话。
  • 事后分析:开启慢查询日志(slow_query_log=ON),并设置 log_queries_not_using_indexes=ON,可捕获所有未使用索引的查询,无论其执行时间长短。
  • 连接池视角:当慢查询堆积时,连接池中的连接被长时间占用,导致 active 连接数飙升,idle 连接数归零,最终触发连接池耗尽。
核心结论:慢查询的判定不是终点,而是连接池治理与熔断降级策略的起点。只有将执行时间、扫描行数、索引使用情况三者结合,才能准确识别出真正威胁系统稳定性的“危险查询”。