视图查询没走索引,大概率是谓词未下推至基表扫描节点,执行计划中基表扫描行预估巨大、filter出现在最外层且where条件未出现在access predicates中,常见诱因包括group by、distinct、union、窗口函数、非确定性函数、嵌套过深、字段表达式或join字段类型/collation不一致。

视图查询没走索引,大概率是谓词没下推到基表扫描节点
执行计划里基表那一行(比如 Seq Scan 或 TABLE ACCESS FULL)如果 rows 预估巨大、Filter 出现在最外层,而 WHERE 条件根本没出现在扫描节点的 Access Predicates 里,就说明优化器放弃了下推。这不是视图“写得不好”,而是它内部结构触发了物化路径。
常见诱因包括:
- 视图定义含
GROUP BY、DISTINCT、UNION、窗口函数或非确定性函数(如NOW()) - 嵌套三层以上,尤其某层用了
LIMIT或OFFSET,导致优化器对中间结果集大小严重误判 - 视图字段用了表达式,比如
UPPER(name),破坏了列的可下推性;即使外层写WHERE UPPER(name) = 'ABC',也很难命中基表name索引
嵌套视图 + JOIN 导致索引失效,先查字段类型和 COLLATION 是否一致
视图本身不存数据,执行时会把所有层级展开成一条 SQL。如果展开后 JOIN 条件两边字段类型不匹配(比如 users.id INT vs logs.user_id VARCHAR),或字符集/排序规则不同(如 utf8mb4_general_ci vs utf8mb4_0900_as_cs),优化器就无法用索引做等值查找——EXPLAIN 里直接显示 type = ALL、key = NULL。
验证方式:
- 用
SHOW FULL COLUMNS FROM table_name LIKE 'col_name'(MySQL)或\d+ table_name(PostgreSQL)比对字段完整定义 - 检查
Collation列是否完全一致;只改CHARACTER SET不同步COLLATE是无效的 - 避免在
ON子句里写t1.id = t2.id OR (t1.id IS NULL AND t2.id IS NULL)这类逻辑,它既破坏索引,又干扰估算
Oracle 的 NESTED LOOPS 里内表没走索引,重点看 ACCESS_PREDICATES 是否为空
在 AWR 报告或 DBA_HIST_SQL_PLAN 中,如果内表连接条件只出现在 FILTER_PREDICATES,而 ACCESS_PREDICATES 为空,说明 NL 没走索引查找,而是全表扫描后过滤。典型表现是 ROWS_PROBED 极高但每次只返回几行。
实操要点:
- 给内表建组合索引时,必须把驱动表的等值条件列放前面,例如
orders.cust_id = customers.id,索引应为(cust_id, order_date),不是单列cust_id -
NESTED LOOPS不支持并行;就算加了PXhint,内表仍是串行访问 - 函数索引(如
UPPER(name))无法用于 NL 的ACCESS,除非连接条件完全匹配该函数表达式
达梦 DM8 执行计划显示 INDEX FAST FULL SCAN,其实没走 B 树索引逻辑
INDEX FAST FULL SCAN 在达梦里本质是并行扫索引叶节点,不走 B 树路径,也不利用有序性,和全表扫描代价接近。真正有效的索引访问是 INDEX RANGE SCAN 或 INDEX UNIQUE SCAN。如果 v$plan_table 的 object_name 字段为空或显示表名,说明索引根本没参与访问路径。
高频失效场景:
- 谓词污染:对索引列用
UPPER(col)、col + 0、LIKE '%abc',或隐式转换如WHERE id = '123'(id 是 NUMBER) - 统计失真:大批量 DML 后未运行
DBMS_STATS.GATHER_TABLE_STATS,优化器误判回表成本 - 选择率超阈值:达梦默认当
WHERE status = 1返回行数占比 >15% 时强制全表扫描,可通过SP_SET_PARA_VALUE(1, 'optimizer_index_cutoff', 25)调整
真正卡住性能的,往往不是“要不要建索引”,而是视图展开后那条 SQL 的谓词能不能落到基表扫描上,以及 JOIN 字段能不能被优化器信任——这两点一错,索引再全也没用。










