Oracle无法全局禁止全表扫描,只能通过SQL Hint(如/+ INDEX(t idx_col) /)强制单条语句走索引;权限和参数均不支持禁用FTS,优化器始终基于成本自主选择访问路径。
oracle 没有提供“限制用户只能走索引、禁止全表扫描”的全局开关或权限级配置。所谓“强制走索引”,本质是通过 sql 级别的 /*+ index(...) */ 或 /*+ index_only(...) */ hint 显式干预单条语句的执行计划,而非对用户行为做策略性封禁。
为什么不能靠用户权限禁止全表扫描
Oracle 的权限体系(如 SELECT、CREATE SESSION)控制的是“能不能查”,不控制“怎么查”。即使授予最小权限,只要用户能执行 SELECT,优化器仍可能基于统计信息、谓词选择率、索引可用性等因素自主选择 FULL 访问路径——这是优化器职责范围内的合法决策。
- 没有
NO_FULL_SCAN权限或系统参数可全局禁用 FTS -
ALTER SYSTEM SET "_optimizer_ignore_hints"=TRUE会全局禁用所有 Hint,但这是高危操作,且不区分用户 - Profile 或 Resource Manager 只能限制 CPU/IO/执行时间,无法约束访问路径
真正可行的控制手段:SQL 层面显式 Hint
若业务逻辑明确要求某类查询必须走索引(例如高频点查、大表分页),唯一可靠方式是在 SQL 中嵌入 Hint,并确保该 SQL 被固定使用(如封装为视图、存储过程或应用层模板):
- 对单表点查:用
/*+ INDEX(t idx_col) */,例如SELECT /*+ INDEX(emp emp_id_idx) */ name FROM emp WHERE id = 123 - 确保只读取索引覆盖列:用
/*+ INDEX_ONLY(t idx_col) */,避免回表(前提是SELECT列全部在索引中) - 避免 Hint 失效:索引名必须准确(区分大小写)、表别名需与 Hint 中一致、索引状态为
VALID - 慎用
INDEX_FULL_SCAN或INDEX_FAST_FULL_SCAN:它们仍是索引扫描,但语义不同,不等价于INDEX
Hint 容易失效的典型场景
即使写了 Hint,Oracle 也可能忽略它,常见原因包括:
- Hint 中的索引不存在或已失效(
SELECT status FROM dba_indexes WHERE index_name = 'IDX_NAME') - 查询条件未匹配索引引导列(如复合索引
(a,b,c),但WHERE b = 1无法触发索引范围扫描) - 优化器判定索引扫描成本高于全表扫描(例如小表、高选择率谓词、统计信息陈旧)
- Hint 语法错误:漏掉表别名、括号不匹配、索引名拼错,此时 Hint 被静默忽略(不会报错)
- 启用了自适应执行计划(Oracle 12c+),运行时可能动态切换为 FTS,Hint 仅影响初始计划
替代思路:从源头减少 FTS 诱因
与其强行“禁止 FTS”,不如让优化器自然倾向索引:
- 定期收集统计信息:
DBMS_STATS.GATHER_TABLE_STATS,尤其对大表和频繁更新列 - 避免在索引列上使用函数或表达式:
WHERE UPPER(name) = 'ABC'会跳过索引,改用函数索引或WHERE name = 'abc' - 谨慎使用
OR、NOT IN、LIKE '%xxx',这些极易触发 FTS - 对低选择率查询(如
WHERE status IN ('A','B')占比 >15%),FTS 反而是合理选择——强行索引反而更慢
真正需要警惕的不是“有没有全表扫描”,而是“为什么不该走索引却走了”。Hint 是手术刀,不是安全锁;依赖它前,先确认统计信息、谓词写法、索引设计是否合理——否则再精准的 Hint 也救不了病态的 SQL。


















