Oracle 索引快速全扫描(Index Fast Full Scan)


在 Oracle 中,除了常见的「索引范围扫描」「全表扫描」之外,还有一类常被忽视却极具性价比的访问路径——Index Fast Full Scan(IFFS)。它把索引本身当成一张「瘦表」来读,不经过表,多块 I/O 直扫所有叶块,常能在「只查索引列」的场景下带来意想不到的 I/O 与性能收益。


IFFS 是什么?一句话记住它

把索引当成表,多块 I/O 全扫所有叶块;不走 ROWID 回表,不按顺序返回行。

关键词:瘦表、多块读、无序返回、不回表


触发条件:优化器什么时候会选 IFFS?

必要条件说明
查询列全部在索引里任何需要的列都包含在索引键或包含列中,无需回表。
统计信息可信优化器认为扫描索引的代价比全表扫描低。
无排序需求IFFS 无法按索引顺序返回数据,若 SQL 有 ORDER BY 与索引顺序一致,则优化器倾向选择 INDEX FULL SCAN(有序)。

工作原理拆解

  1. 多块 I/O:一次 DB_FILE_MULTIBLOCK_READ_COUNT 个块,像全表扫描一样高效。
  2. 读取结构:根块、分支块、叶块全部读入缓存,但仅处理叶块中的索引条目
  3. 并行友好:可以开启并行,典型 OLAP/报表场景利器。
  4. 无法避免排序:因为叶块可能按块顺序而非键顺序返回,需要额外 SORT 操作才能满足 ORDER BY

强制 IFFS:hint 语法

SELECT /*+ INDEX_FFS(<表别名> <索引名>) */ ...

示例:统计 departments 表总行数,索引已覆盖所需列。

SELECT /*+ INDEX_FFS(departments dept_id_pk) */ COUNT(*)
 FROM departments;

执行计划:

-------------------------------------------------------------------------
| Id | Operation           | Name       | Rows | Cost (%CPU)| Time     |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT     |           |   1 |   2 (100) |         |
| 1 | SORT AGGREGATE     |           |   1 |           |         |
| 2 |   INDEX FAST FULL SCAN| DEPT_ID_PK |   27 |   2   (0) | 00:00:01 |

Cost 只有 2,远低于全表扫描。


5. 典型应用场景

场景示例 SQL收益
聚合统计SELECT COUNT(*) FROM sales WHERE sale_date >= DATE '2025-01-01'索引已包含 sale_date,无需回表。
去重计数SELECT COUNT(DISTINCT customer_id) FROM orders覆盖索引避免表扫描。
报表列投影SELECT id, name FROM departments只有两列,且都在索引中。

6. 注意事项与踩坑

  1. 不回表 ≠ 一定更快:若索引远大于表(高碎片、低删除空间),全表扫描可能更优。
  2. 无法避免排序:需要排序时,额外 SORT 可能抵消 I/O 优势。
  3. 并行度/*+ INDEX_FFS PARALLEL(4) */ 可提速,但会占用 CPU 与 I/O。
  4. 统计信息:缺失或过期时,优化器可能误判成本,导致走错计划。

维度INDEX FAST FULL SCAN
适用查询列全部在索引内
优点像扫表一样扫索引,I/O 少,可并行
缺点无序返回,无法避免排序
关键词INDEX_FFS hint、多块读、不回表 “列全在索引,不回表;多块 I/O 跑得快,顺序乱要排序。”

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部