视图中使用DISTINCT会导致优化器无法下推WHERE条件,因其强制采用TEMPTABLE算法,先全量物化中间结果并丢失索引上下文,再执行外层过滤,致使即使基表有合适索引也无法生效。

视图里加DISTINCT会让优化器放弃下推WHERE条件
因为DISTINCT本质是全局去重操作,必须看到全部数据才能判断某行是否重复。优化器没法把外层WHERE条件“提前”应用到基表扫描阶段——它得先完成去重,再过滤,否则可能漏掉本该保留的行。
DISTINCT触发TEMPTABLE算法,中间结果脱离索引上下文
MySQL默认对含DISTINCT的视图设为ALGORITHM=TEMPTABLE,执行时先物化成临时表,再对外层WHERE过滤。临时表没有原始列的索引信息,优化器根本看不到user_id或status字段是否可走索引。
-
SHOW CREATE VIEW view_name若显示ALGORITHM=TEMPTABLE,基本可断定谓词无法下推 - 执行计划中出现
Using temporary或type=ALL且key=NULL,就是典型表现 - 哪怕基表有
INDEX (tenant_id, status),视图查询仍可能全表扫描
外层WHERE被强制后置,顺序颠倒导致索引失效
视图定义一旦固化DISTINCT,所有调用都继承这个行为。你加WHERE tenant_id = 123,优化器往往先做去重再过滤,而不是用索引快速定位tenant_id = 123的行。
- 多表JOIN后加DISTINCT,还会隐式触发临时表+排序,进一步放大I/O开销
-
EXPLAIN里看到Filter操作符在最外层,而基表扫描节点rows值巨大,就是顺序错乱的铁证 - PostgreSQL虽支持
DISTINCT ON,但写进视图会破坏跨数据库兼容性,且仍不解决下推问题
真正难察觉的是:它不报错,只悄悄变慢
DISTINCT在视图里像一个静默放大器——每次查询都消耗额外内存和磁盘读,但SQL语法完全合法,日志里也没有警告。最容易被忽略的点是:你改了基表索引,却忘了视图逻辑本身已阻断优化路径。

















