Oracle SQL Hint 详解

Oracle SQL Hint 详解

适用版本:Oracle Database 10g / 11g / 12c / 19c / 23ai 文档版本:v1.0 / 2026-07


1. 概述

SQL Hint 影响 CBO 决策[1]:

详细见:Oracle SQL Hint 详解


2. 语法

SELECT /*+ HINT */ ...
INSERT /*+ HINT */ ...
UPDATE /*+ HINT */ ...
DELETE /*+ HINT */ ...
MERGE /*+ HINT */ ...

3. 优化器

3.1 优化模式

/*+ RULE */                  -- RBO
/*+ FIRST_ROWS(n) */         -- 前几行快
/*+ FIRST_ROWS_10 */
/*+ FIRST_ROWS_100 */
/*+ FIRST_ROWS_1000 */
/*+ ALL_ROWS */              -- 全部行(吞吐量)
/*+ CHOOSE */                -- 选择

3.2 示例

SELECT /*+ FIRST_ROWS(10) */ * FROM employees WHERE name = 'Alice';
SELECT /*+ ALL_ROWS */ * FROM employees;

4. 索引

4.1 选择

/*+ INDEX(t idx_name) */              -- 指定索引
/*+ INDEX(t) */                       -- 任意索引
/*+ INDEX(t idx1 idx2) */             -- 多个
/*+ NO_INDEX(t idx_name) */           -- 不用
/*+ INDEX_FFS(t idx_name) */          -- Fast Full Scan
/*+ INDEX_SS(t idx_name) */           -- Skip Scan
/*+ INDEX_DESC(t idx_name) */         -- 降序
/*+ INDEX_ASC(t idx_name) */          -- 升序
/*+ INDEX_COMBINE(t) */               -- 组合

4.2 示例

SELECT /*+ INDEX(e idx_emp_name) */ * FROM employees e WHERE name = 'Alice';
SELECT /*+ INDEX_FFS(e idx_emp_name) */ name FROM employees e;

5. 表访问

/*+ FULL(t) */              -- 全表扫描
/*+ ROWID(t) */             -- ROWID
/*+ CLUSTER(t) */           -- 簇
/*+ HASH(t) */              -- 哈希

5.1 示例

SELECT /*+ FULL(e) */ * FROM employees e WHERE dept_id = 10;

6. JOIN

6.1 方法

/*+ USE_NL(t1 t2) */        -- Nested Loop
/*+ USE_HASH(t1 t2) */      -- Hash Join
/*+ USE_MERGE(t1 t2) */     -- Sort Merge
/*+ NO_USE_NL(t1 t2) */
/*+ NO_USE_HASH(t1 t2) */
/*+ NO_USE_MERGE(t1 t2) */

6.2 顺序

/*+ LEADING(t1 t2) */       -- 指定顺序
/*+ ORDERED */              -- FROM 顺序
/*+ SWAP_JOIN_INPUTS(t) */  -- 交换输入

6.3 示例

SELECT /*+ USE_HASH(e d) LEADING(e d) */ *
FROM employees e, departments d
WHERE e.dept_id = d.id;

SELECT /*+ USE_NL(e d) */ *
FROM employees e, departments d
WHERE e.dept_id = d.id;

详细见:Oracle JOIN 连接方式


7. 并行

7.1 并行度

/*+ PARALLEL(t n) */        -- 并行度 n
/*+ PARALLEL(t) */          -- 自动
/*+ NOPARALLEL(t) */        -- 串行
/*+ PARALLEL_INDEX(t idx n) */

7.2 PQ

/*+ PQ_DISTRIBUTE(t, distribution) */
/*+ PQ_FILTER(...) */

7.3 示例

SELECT /*+ PARALLEL(s 8) */ SUM(amount) FROM sales s;

详细见:Oracle 并行查询详解


8. 子查询

/*+ PUSH_SUBQ */            -- 推进子查询
/*+ NO_PUSH_SUBQ */
/*+ MERGE */                -- 合并视图
/*+ NO_MERGE */
/*+ UNNEST */               -- 展开
/*+ NO_UNNEST */
/*+ STAR_TRANSFORMATION */  -- 星型转换

8.1 示例

SELECT /*+ MERGE(v) */ * FROM (
  SELECT * FROM employees
) v;

SELECT /*+ UNNEST(@sub) */ * FROM employees e
WHERE EXISTS (SELECT /*+ QB_NAME(sub) */ 1 FROM departments WHERE id = e.dept_id);

9. 视图

/*+ MERGE(v) */             -- 视图合并
/*+ NO_MERGE(v) */
/*+ PUSH_PRED(v) */         -- 推进谓词
/*+ NO_PUSH_PRED(v) */

10. 数据加载

/*+ APPEND */               -- 直接路径
/*+ APPEND_VALUES */        -- VALUES 直接路径
/*+ NOAPPEND */

10.1 示例

INSERT /*+ APPEND */ INTO big_table SELECT * FROM source;

11. 其他

/*+ DRIVING_SITE(t) */      -- 远程执行
/*+ CARDINALITY(t, n) */    -- 设置基数
/*+ OPT_PARAM(name, value) */ -- 参数
/*+ MONITOR */              -- 监控
/*+ NO_MONITOR */
/*+ GATHER_PLAN_STATISTICS */ -- 统计
/*+ RESULT_CACHE */         -- 结果缓存
/*+ NO_RESULT_CACHE */
/*+ NO_UNNEST */
/*+ RESULT_MODE(...) */
/*+ XMLINDEX_REWRITE */

11.1 示例

SELECT /*+ CARDINALITY(e, 10000) */ * FROM employees e;
SELECT /*+ OPT_PARAM('optimizer_index_cost_adj', 50) */ * FROM employees;
SELECT /*+ GATHER_PLAN_STATISTICS */ * FROM employees;

12. Hint 错误

12.1 不生效

- 语法错误
- 别名错误
- 索引不存在
- 不适用

12.2 检查

-- 查看 Hint 报告(19c+)
SELECT sql_fulltext FROM v$sql ...;
-- 或
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format => 'ALL')));

13. QB_NAME

SELECT /*+ QB_NAME(main) LEADING(@sub e) */ *
FROM employees e
WHERE EXISTS (SELECT /*+ QB_NAME(sub) */ 1 FROM departments WHERE id = e.dept_id);

14. 应用场景

14.1 索引强制

SELECT /*+ INDEX(e idx_emp_email) */ * FROM employees e WHERE email = '...';

14.2 全表

SELECT /*+ FULL(e) */ * FROM employees e WHERE dept_id = 10;
-- 数据量大部分

14.3 JOIN

-- 大表
SELECT /*+ USE_HASH(a b) */ ...
-- 小表
SELECT /*+ USE_NL(a b) */ ...

14.4 并行

SELECT /*+ PARALLEL(t 8) */ COUNT(*) FROM big_table t;

14.5 直接路径

INSERT /*+ APPEND */ INTO target SELECT * FROM source;

15. 替代

15.1 Profile

-- SQL Profile(Hint 等效)
EXEC DBMS_SQLTUNE.ACCEPT_SQL_PROFILE(...);

15.2 Baseline

-- SQL Plan Baseline
EXEC DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(...);

详细见:Oracle SQL 调优顾问Oracle SQL Plan Baseline 基线

15.3 统计

- 直方图
- 扩展统计
- 系统

16. 何时使用

- CBO 错误
- 临时解决
- 测试
- 验证假设

16.1 不建议

- 长期
- 数据变化
- 维护

17. 验证

17.1 执行计划

EXPLAIN PLAN FOR SELECT /*+ INDEX(t idx) */ ...;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY));

17.2 实际

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('&sql_id'));
-- Note 部分 Hint

详细见:Oracle 执行计划详解


18. 最佳实践

  1. 谨慎使用:最后手段
  2. 统计优先:基础
  3. Profile/Baseline:替代
  4. 测试:验证
  5. 注释:说明
  6. 监控:稳定
  7. 数据变化:调整
  8. 版本兼容:检查
  9. 别名正确:生效
  10. 文档化:维护

19. 参考资料

[1] Oracle Database SQL Tuning Guide 19c, “Hints” https://docs.oracle.com/en/database/oracle/oracle-database/19/tgsql/influencing-the-optimizer.html