sql查询慢的核心是全表扫描、索引失效、数据传输多或执行计划差;优化需聚焦少算、快找、少传,通过合理索引、尽早过滤、冷热分离、读写分离、物化预计算及执行计划分析实现。

大数据量下 SQL 查询慢,核心问题通常是全表扫描、索引失效、数据传输过多或执行计划不合理。优化不是堆硬件,而是让数据库“少算、快找、少传”。
合理设计并使用索引
索引是提速最直接的手段,但必须用对。单列索引适合等值查询(WHERE status = 'done'),联合索引要注意最左前缀原则(INDEX (a, b, c) 可用于 WHERE a=1 AND b=2,但不能用于 WHERE b=2)。避免在索引列上做函数操作(如 WHERE YEAR(create_time) = 2024 会跳过索引),改写为范围查询:WHERE create_time >= '2024-01-01' AND create_time 。
- 定期用 EXPLAIN 检查查询是否命中索引,重点关注 type(尽量为 ref 或 range)、key(实际使用的索引名)、rows(预估扫描行数)
- 区分高选择性字段(如 user_id)和低选择性字段(如 gender),后者建索引收益低,甚至拖慢写入
- 删除长期未被使用的索引,减少维护开销和写入延迟
减少数据扫描与传输量
查得准,比查得快更重要。避免 SELECT *,只取业务真正需要的字段;分页慎用 LIMIT M,N(当 M 很大时,MySQL 仍需扫描前 M 行),改用游标式分页(如记录上一页最大 id,用 WHERE id > last_id LIMIT N)。
- 大表关联优先走索引字段,避免 JOIN 多张大表后笛卡尔积爆炸
- 用 WHERE 尽早过滤,而不是靠应用层后过滤;子查询若可转为 JOIN,通常更高效
- 聚合类查询(如 COUNT、SUM)注意是否真的需要精确值——近似统计(如 MySQL 的 INFORMATION_SCHEMA.TABLES 中的 TABLE_ROWS)或采样估算可大幅提速
拆分与归档冷热数据
单表超千万行后,性能拐点明显。按时间或业务维度水平拆分(如按月分表 order_202401、order_202402),配合分区表(PARTITION BY RANGE/YEAR)让查询自动定位到相关分区,避免扫全表。
- 将历史订单、日志等冷数据归档到独立库或列存引擎(如 ClickHouse),主库只留近期活跃数据
- 读写分离 + 应用路由:报表类查询走从库,且可设置从库延迟容忍阈值,避免查到过期数据
- 高频聚合结果提前物化(如每日 UV 预计算存入汇总表),查询直接读结果,不实时算
善用执行计划与监控工具
优化不能靠猜。开启慢查询日志(slow_query_log=ON,设好 long_query_time),用 pt-query-digest 分析瓶颈 SQL;用 Performance Schema 或 sys schema 查看锁等待、IO 瓶颈、内存排序是否溢出磁盘。
- 关注 Using filesort 和 Using temporary 提示,说明排序或分组未走索引,需检查 ORDER BY / GROUP BY 字段是否包含在索引中
- 连接池配置要匹配实际并发,过小导致排队,过大压垮数据库;连接空闲超时、SQL 超时等参数需按场景调优
- 批量写入用 INSERT ... VALUES (...), (...), (...) 替代多条单 INSERT;更新/删除加 WHERE 条件并确保有索引,防全表锁
不复杂但容易忽略。关键是建立“观察—分析—验证”的闭环,每次改动都用真实数据对比耗时与资源消耗。









