DISTINCT 变慢是因为其本质是隐式 GROUP BY,会触发临时表和文件排序;需用匹配顺序的联合覆盖索引优化,或改写为 GROUP BY 启用松散索引扫描。

为什么 DISTINCT 会变慢
MySQL 的 DISTINCT 本质是去重,执行时通常会触发临时表(Using temporary)和文件排序(Using filesort),尤其当字段没索引、结果集大或涉及多列组合时,性能下降明显。它不是语法糖,而是隐式 GROUP BY,MySQL 5.7+ 后底层基本等价于 GROUP BY 字段列表。
加索引不一定管用,关键看覆盖和顺序
对 SELECT DISTINCT col1, col2 加单列索引 (col1) 或 (col2) 通常无效;必须建联合索引且满足最左前缀原则,并尽可能覆盖查询字段:
- 理想索引:
ALTER TABLE t ADD INDEX idx_distinct (col1, col2)—— 能让 MySQL 直接遍历索引树去重,避免回表和临时表 - 如果还查了
col3(如SELECT DISTINCT col1, col2, col3),单靠(col1, col2)索引仍要回表,此时应考虑覆盖索引:(col1, col2, col3) - 注意:索引列顺序必须和
DISTINCT字段顺序一致,DISTINCT col2, col1无法利用(col1, col2)索引
用 GROUP BY 替代 DISTINCT 常能启用松散索引扫描
在某些场景下,显式写 GROUP BY 比 DISTINCT 更容易触发优化器的松散索引扫描(Loose Index Scan),大幅减少扫描行数。前提是:分组字段有合适索引,且无聚合函数或 HAVING 子句干扰。
SELECT DISTINCT city, district FROM users; -- 可尝试改写为: SELECT city, district FROM users GROUP BY city, district;
两者语义等价,但后者在有 (city, district) 索引时,可能跳过重复值区间,而前者有时仍走紧凑扫描(Tight Index Scan)。
一款基于PHP+MYSQL开发的企业网站管理软件,具有灵活的栏目内容管理功能和丰富的网站模版,可用于创建各种企业网站。v5.1版本支持了PHP5+MYSQL5环境,前台网站插件开放源码,更利于个性化的网站开发。具有以下功能特点和优越性:[>]模版精美实用具有百款适合企业网站的精美模版,并在不断增加中[>]多语言支持独立语言包,支持GBK,UTF8编码方式,可用于创建各种语言的网站[&g
避免 SELECT * + DISTINCT 和大字段参与去重
DISTINCT 对所有选中列做哈希/排序比对,若包含 TEXT、BLOB 或长 VARCHAR,不仅内存占用高,还可能触发磁盘临时表(Created_tmp_disk_tables 上升)。常见错误包括:
-
SELECT DISTINCT *, created_at FROM logs——*让优化器无法裁剪,且大字段拖慢整个去重流程 -
SELECT DISTINCT CONCAT(name, '-', id) AS key FROM t—— 表达式结果无法走索引,强制全表计算再去重 - 正确做法:只选必要字段;用主键或唯一标识替代长文本拼接;必要时先子查询过滤再 DISTINCT
真正卡顿的地方往往不在语法本身,而在没意识到 DISTINCT 是“隐式 GROUP BY + 全字段比对”——索引是否覆盖、字段是否可比较、结果集是否被业务逻辑悄悄撑大,这些细节比记住语法更重要。









