mysql查询慢是什么原因_mysql慢查询原因分析

12次阅读

最常见的原因是没加索引或索引失效导致全表扫描:WHERE、ORDER BY、JOIN 字段无有效索引时 MySQL 需逐行扫描;EXPLAIN 显示 type 为 ALL、key 为 NULL、rows 远超匹配数即为典型表现;复合索引须遵守最左前缀原则;OR 条件中任一字段无索引、对索引字段用函数、隐式类型转换均会导致索引失效;SELECT * 或深分页(如 LIMIT 100000,20)会大幅降低性能,应只查必要字段并改用游标分页。

mysql 查询慢是什么原因_mysql 慢查询原因分析

没加索引或索引失效导致全表扫描

这是最常见的原因:当 WHEREORDER BYJOIN 字段上没有有效索引,MySQL 就只能一行行读完整张表。哪怕只有几万行,I/O 和 CPU 开销也会陡增。

检查方法很简单:EXPLAIN SELECT ……type 是否为 ALL(全表扫描),key 是否为 NULLrows 是否远超实际匹配数。

  • 复合索引要注意最左前缀原则,(a,b,c) 无法加速 WHERE b = ?
  • OR 条件中只要有一边没索引,整条语句可能退化为全表扫描
  • 对索引字段做函数操作(如 WHERE YEAR(create_time) = 2024)会直接让索引失效
  • 隐式类型转换 (比如字符串字段查数字:WHERE mobile = 13800138000)也可能绕过索引

查询返回了太多无用数据

SELECT * 或没加 LIMIT 的分页查询,在数据量大时非常危险。网络传输、内存排序、客户端处理都会拖慢整体响应。

典型例子:SELECT * FROM orders ORDER BY created_at DESC LIMIT 100000, 20 —— MySQL 仍要先定位前 100000 行,再取 20 行,效率极低。

  • 只查真正需要的字段,避免 *
  • 深分页优先改用游标方式(比如记录上一页最大 id,下一页查 WHERE id)
  • 大结果集导出类需求,考虑用 mysqldump 或服务端流式读取,别在应用层一次拉完

锁等待和事务长跑阻塞查询

慢查询不一定是 SQL 本身慢,也可能是被别的连接卡住了。比如一个未提交的事务长时间持有行锁 / 表锁,后续所有涉及这些行的 SELECT …… FOR UPDATE 或写操作都会排队等待。

查当前阻塞情况:SHOW ENGINE INNODB STATUSGTRANSACTIONS 部分;或者查 information_schema.INNODB_TRXINNODB_LOCK_WAITS

  • 避免在事务里做 HTTP 调用、文件读写等外部耗时操作
  • 写操作尽量短平快,别把 UPDATE 套在大循环里
  • 读多写少场景可考虑开启 READ COMMITTED 隔离级别,减少锁范围
  • 注意 AUTO_COMMIT=OFF 后忘记 COMMIT 的“幽灵事务”

服务器资源或配置不合理

即使 SQL 写得再好,硬件跟不上或参数设错也会拖慢查询。比如 sort_buffer_size 太小导致 ORDER BY 落盘排序,innodb_buffer_pool_size 远小于数据量造成频繁磁盘读。

关键指标要看:SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads'(磁盘读次数)vs 'Innodb_buffer_pool_read_requests'(总读请求),比值超过 1% 就说明缓存严重不足。

  • 缓冲池大小建议设为物理内存的 50%–75%,但别超过可用内存,否则触发系统 OOM
  • 临时表过大(Created_tmp_disk_tables 高)说明 tmp_table_sizemax_heap_table_size 设太小
  • 高并发下 innodb_thread_concurrency 设为 0(默认不限制)通常更稳,设死值反而可能限制吞吐

慢查询背后往往是多个因素叠加,比如一条没索引的语句在缓冲池不足时,既触发大量磁盘 I/O,又因排序落盘进一步放大延迟。定位时别只盯着 SQL,得从执行计划、锁状态、服务器指标三层一起看。

text=ZqhQzanResources