查询慢主因是where条件未走索引,如like左模糊、字段函数运算;应使用explain分析执行计划,建联合索引、避免运算、显式指定字段、慎用count(*),优先定位真凶再优化。

WHERE 条件没走索引,查得慢到怀疑人生
绝大多数大数据量查询慢,不是数据量大本身的问题,而是 WHERE 条件字段没命中索引。比如对 status 字段做 LIKE '%pending',或在条件里对字段用了函数:WHERE DATE(created_at) = '2024-01-01' —— 这两种写法都会让索引失效。
实操建议:
- 用
EXPLAIN看执行计划,重点盯type(最好是ref或range)、key(是否用了索引)、rows(预估扫描行数) -
status类低基数字段单独建索引意义不大,但和高频过滤字段组合成联合索引就有效,比如(tenant_id, status, created_at) - 避免在索引字段上做运算或类型转换,把
WHERE DATE(created_at) = ...改成WHERE created_at >= '2024-01-01' AND created_at
OFFSET 越大越卡,分页查不动了
用 LIMIT 10000, 20 查第 501 页?数据库得先扫出前 10020 行再丢掉前面的,IO 和 CPU 成倍涨。这不是 SQL 写得不好,是 OFFSET 语义本身不适合深分页。
实操建议:
- 改用游标分页:记住上一页最后一条的
id或created_at,下一页查WHERE id > 12345 ORDER BY id LIMIT 20 - 如果必须用页码,且数据相对静态,可提前物化分页映射(比如用 Redis 缓存
page:500 → offset:99980),但要注意数据变更时的失效策略 - 别在
ORDER BY字段上用函数,比如ORDER BY UPPER(name),会强制全表排序,无法利用索引排序能力
SELECT * 拉太多字段,网络和内存都吃不消
查 100 万行,每行多选 3 个 TEXT 字段,结果集可能从 200MB 涨到 2GB。不仅慢,还容易触发 MySQL 的 max_allowed_packet 错误,或者压垮应用层内存。
云点滴客户解决方案是针对中小企业量身制定的具有简单易用、功能强大、永久免费使用、终身升级维护的智能化客户解决方案。依托功能强大、安全稳定的阿里云平 台,性价比高、扩展性好、安全性高、稳定性好。高内聚低耦合的模块化设计,使得每个模块最大限度的满足需求,相关模块的组合能满足用户的一系列要求。简单 易用的云备份使得用户随时随地简单、安全、可靠的备份客户信息。功能强大的报表统计使得用户大数据分析变的简单,
实操建议:
- 永远显式列出需要的字段,删掉所有
*,尤其是别带json、text、blob类大字段,除非真要用 - 大字段单独建宽表或异步加载:主表只存 ID 和摘要,详情走另一条轻量查询
- 注意 ORM 的懒加载陷阱,比如 Django 的
select_related没配好,一次查出几十张表的全部字段
统计 COUNT(*) 卡住,又不能加缓存
对上亿行表执行 COUNT(*),InnoDB 得扫聚簇索引,哪怕有索引也绕不开。有些场景(比如后台实时看板)确实要准数,但硬查就是扛不住。
实操建议:
- 确认是否真的需要精确值:用户侧显示“约 1200 万条”比“12003456 条”更合理,可用采样估算,比如
SELECT (COUNT(*) * 10) FROM t TABLESAMPLE BERNOULLI (10)(PostgreSQL) - MySQL 8.0+ 可考虑用
INFORMATION_SCHEMA.INNODB_TABLESTATS中的n_rows近似值,误差通常在 ±10%,但不保证实时 - 如果业务允许延迟,用定时任务把统计结果写进汇总表,查询走
SELECT total_count FROM stats_summary WHERE table_name = 'orders'
最麻烦的往往不是怎么优化,而是搞不清哪条查询真正拖慢了整体——先用慢日志 + EXPLAIN 定位,别一上来就加索引或分库分表。索引建多了反而让写入变慢,而且优化器也可能选错执行路径。









