MySQL 查询慢,除索引问题外,核心原因集中在数据设计、查询逻辑、硬件资源、数据库配置、锁与事务五大维度,具体可分为以下几类:
1. 数据设计与存储问题
-
数据量过大且未分区:表数据量达千万/亿级时,若未按时间、地域等维度做分区(如 PARTITION BY RANGE),即使有索引,也需扫描全表分区,导致耗时增加。
-
数据倾斜严重:分库分表场景下,某分片数据量远超其他(如某地区订单占总量70%),查询命中“热点分片”会因单节点负载过高拖慢速度。
-
表结构设计不合理:包含大字段(如 TEXT、BLOB)且未拆分,查询时会额外加载冗余数据;或存在大量冗余字段,增加数据读取和处理成本。
-
无效数据过多:表中堆积大量历史无效数据(如3年前的日志),未定期归档/清理,导致查询需扫描更多数据。
2. 查询语句本身低效
-
复杂逻辑与计算:包含多层嵌套子查询(如 SELECT ... FROM (SELECT ... FROM ...))、多表笛卡尔积关联(未加有效关联条件)、高频聚合排序(如 COUNT(DISTINCT)、GROUP BY + ORDER BY),会大幅增加 MySQL 计算压力。
-
返回数据量过大:未用 LIMIT 限制结果条数,或一次性查询全量明细数据(如导出10万条数据),网络传输和结果集加载时间占比过高。
-
过滤条件“破索引”:使用 NOT IN、!=、OR(非索引字段组合)、函数包裹索引字段(如 DATE(create_time) = '2024-01-01'),导致索引失效,触发全表扫描。
3. 硬件与资源瓶颈
-
CPU 不足:高并发查询、复杂聚合计算(如 SUM、GROUP BY)会耗尽 CPU 资源,导致查询排队等待。
-
内存不足:MySQL 缓冲池(innodb_buffer_pool_size)配置过小,无法缓存热点数据,频繁触发磁盘 IO(磁盘读写速度远低于内存),拖慢查询。
-
磁盘性能差:使用机械硬盘(HDD)而非固态硬盘(SSD),或磁盘 IO 已达瓶颈(如同时有大量写入/读取操作),数据读取速度受限。
-
网络延迟:若应用与 MySQL 不在同一机房,或网络带宽不足,查询请求和结果传输会因网络卡顿耗时增加。
4. 数据库配置不合理
-
缓冲池配置过小:innodb_buffer_pool_size 是 InnoDB 核心缓存,若小于表数据量,热点数据无法常驻内存,需频繁从磁盘加载。
-
连接数超限:max_connections 配置过低,高并发时新查询无法建立连接,需等待现有连接释放。
-
日志刷盘策略激进:innodb_flush_log_at_trx_commit = 1(默认)会每次事务提交都刷盘,虽保证数据安全,但高频写入时会增加磁盘 IO 压力,间接影响查询。
-
查询缓存失效(旧版本):MySQL 8.0 前的查询缓存(query_cache),若表频繁更新会导致缓存失效,反而增加缓存维护开销。
5. 锁与事务影响
-
行锁/表锁竞争:查询涉及的行/表被其他事务加锁(如写事务加排他锁),查询需等待锁释放,产生“锁等待”延迟。
-
长事务阻塞:存在未提交的长事务(如事务执行时间超过10秒),会占用锁资源并阻塞后续查询,尤其在高并发场景下影响显著。
-
事务隔离级别过高:REPEATABLE READ(默认)或 SERIALIZABLE 级别会通过间隙锁、Next-Key Lock 防止幻读,但若查询范围过大,会增加锁冲突概率。