outlint定义时,TO参数传与不传有什么区别?


outlint定义时,TO参数传与不传有什么区别?

1 个赞

前置测试表

sql

-- 建测试表+索引
CREATE TABLE t1(id INT PRIMARY KEY,c1 VARCHAR(20));
CREATE INDEX idx_t1_c1 ON t1(c1);
INSERT INTO t1 VALUES(1,'a'),(2,'b'),(3,'c');
COMMIT;

场景 1:业务 SQL 无 hint → 不使用 TO 子句(推荐最简写法)

1. 创建 Outline

sql

-- 带hint的语句作为基准,不写TO
CREATE OR REPLACE OUTLINE ol_no_to
ON SELECT /*+ INDEX(t1 idx_t1_c1) */ * FROM t1 WHERE c1=?;

2. 执行业务原生 SQL(不带 hint)

sql

SELECT * FROM t1 WHERE c1='a';

生效逻辑

OB 会把 ON 后的语句剔除 hint,得到匹配模板 SELECT * FROM t1 WHERE c1=?,参数化后和业务 SQL 完全匹配,自动追加索引 hint,走索引扫描。

验证是否命中 Outline

sql

EXPLAIN EXTENDED SELECT * FROM t1 WHERE c1='a';
-- 执行计划末尾会显示 Outline: ol_no_to

失效场景

如果业务 SQL 自带 hint,如下语句不会命中上面的 ol_no_to

sql

SELECT /*+ FULL(t1) */ * FROM t1 WHERE c1='a';

场景 2:业务 SQL 自带 hint → 必须使用 TO 子句覆盖原有 hint

1. 创建带 TO 的 Outline

sql

CREATE OR REPLACE OUTLINE ol_use_to
-- 左边:我们期望生效的带正确hint的SQL
ON SELECT /*+ INDEX(t1 idx_t1_c1) */ * FROM t1 WHERE c1=?
-- TO 后:线上真实执行、自带错误hint的原始SQL模板
TO SELECT /*+ FULL(t1) */ * FROM t1 WHERE c1=?;

2. 执行带原生 hint 的业务 SQL

sql

SELECT /*+ FULL(t1) */ * FROM t1 WHERE c1='b';

生效逻辑

匹配模板取自 TO 后的语句,无视业务 SQL 自带的 FULL(t1) 全表扫描 hint,强制替换为 INDEX 索引 hint。

验证命中

sql

EXPLAIN EXTENDED SELECT /*+ FULL(t1) */ * FROM t1 WHERE c1='b';
-- 计划中Outline: ol_use_to,执行计划走索引而非全表扫描

配套常用管理 SQL

  1. 查询已创建的 Outline

sql

SELECT outline_name,sql_text,target_sql_text FROM DBA_OUTLINES;
  • sql_text:ON 后带 hint 的语句
  • target_sql_text:TO 后的匹配语句,无 TO 时该字段为 NULL
  1. 删除 Outline

sql

DROP OUTLINE IF EXISTS ol_no_to;
DROP OUTLINE IF EXISTS ol_use_to;
1 个赞

:mag: 不传 TO <target_stmt> (默认模式)

  • 匹配逻辑 :系统会将你传入的 stmt_with_hint (带 Hint 的语句)进行参数化 (即把常量替换为 ? ),然后与数据库接收到的所有 SQL 进行参数化文本比对。

  • 适用场景 :适用于原始 SQL 本身不含 Hint ,你想通过 Outline 给它“注入”一个执行计划。

  • 示例

sql

编辑

1CREATE OUTLINE ol1 ON SELECT /*+ INDEX(t1 idx1) */ * FROM t1 WHERE c1 = ?;

此时,所有形如 SELECT * FROM t1 WHERE c1 = 100 的 SQL,只要参数化后与 SELECT * FROM t1 WHERE c1 = ? 一致,就会命中这个 Outline。

:dart: 传入 TO <target_stmt>

  • 匹配逻辑 :系统会将 stmt_with_hinttarget_stmt 都进行参数化,只有当两者参数化后完全一致 时,才会将 stmt_with_hint 中的 Hint 应用于 target_stmt

  • 适用场景 :适用于原始 SQL 本身已含 Hint ,但你希望用另一个 Hint 覆盖它,或者你想精确控制哪个 SQL 被绑定。

  • 关键要求stmt_with_hinttarget_stmt 在去掉 Hint 后,必须完全匹配 (包括表名、列名、结构等)。

  • 示例

sql

编辑

1CREATE OUTLINE ol2 ON SELECT /*+ FULL(t1) */ * FROM t1 WHERE c1 = ? TO SELECT /*+ INDEX(t1 idx1) */ * FROM t1 WHERE c1 = ?;

此时,只有当数据库收到的 SQL 是 SELECT /*+ INDEX(t1 idx1) */ * FROM t1 WHERE c1 = 100 时,才会被替换为 FULL(t1) 的执行计划。

1 个赞