核心是让MySQL利用索引有序性跳过排序和临时表,关键在于复合索引需严格匹配WHERE、GROUP BY及SELECT字段顺序,优先包含等值WHERE列,并满足松散扫描条件以触发Loose Index Scan。

核心是让 MySQL 能跳过排序和临时表,直接利用索引的有序性完成分组。关键不在“有没有索引”,而在“索引是否匹配查询结构”。
用对复合索引:覆盖 WHERE、GROUP BY 和 SELECT 字段
索引列顺序必须严格匹配 GROUP BY 的字段顺序,并优先包含 WHERE 条件列。例如:
- 查询是 WHERE status = 'active' GROUP BY dept, role,那就建 (status, dept, role) 复合索引;
- 如果 SELECT 还要返回 AVG(salary),且 salary 不在索引里,就会回表——这时可考虑把 salary 加进索引末尾,形成覆盖索引(但需权衡写入开销);
- 避免只建单列索引,比如 (dept) 或 (role),它们对多列分组几乎无效。
消除 Using temporary 和 Using filesort
这两个提示是性能瓶颈的明确信号。解决方法包括:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 确认执行计划中 type 是 range 或 ref,而不是 ALL;
- 如果 GROUP BY 后还带 ORDER BY,且顺序一致(如都按 dept ASC),索引可复用;若不一致或含 DESC,MySQL 8.0+ 可建降序索引,如 (dept ASC, created_at DESC);
- 不需要结果排序时,显式加上 ORDER BY NULL,能跳过隐式排序逻辑。
区分松散扫描与紧凑扫描,优先触发 Loose Index Scan
松散索引扫描(Loose Index Scan)只读取每个分组的第一条索引记录,效率远高于逐行扫描。它生效需满足:
- 查询无 WHERE 范围条件,或只有等值条件(如 WHERE dept = 'tech');
- GROUP BY 列是索引最左前缀,且未被表达式包裹(如 GROUP BY UPPER(dept) 会失效);
- 聚合函数仅限 MIN()、MAX()、COUNT(*) 等可由索引首尾直接推导的类型。
慎用预聚合,但高频报表场景值得建汇总表
实时 GROUP BY 再快也有上限。对经营类固定口径报表:
- 把每日/每小时聚合结果存入独立汇总表,主键设为分组字段(如 (date, dept));
- 查询时直接查汇总表,避免每次扫描原始流水;
- 注意验证刷新延迟和口径一致性,尤其涉及 AVG、COUNT(DISTINCT) 等不可加指标时不能简单累加。


















