DBMS_ADVISOR不优化PL/SQL逻辑,仅针对可执行SQL语句提供建议;PL/SQL性能瓶颈90%源于嵌套SQL效率,而非控制结构本身。
oracle 19c 的 dbms_advisor 包本身不优化 pl/sql 逻辑,它只处理 sql 语句级的执行计划建议;真正影响 pl/sql 性能的,90% 是其中嵌套的 sql 执行效率,而非 pl/sql 控制结构本身。
为什么 DBMS_ADVISOR 对纯 PL/SQL 块无效
DBMS_ADVISOR(包括 DBMS_SQLTUNE)的输入必须是可解析、可执行的 SQL 语句,例如 SELECT、UPDATE、DELETE 或带绑定变量的 DML。它无法接收 BEGIN ... END; 块、游标定义、循环体或函数体作为输入。
- 你传入一个存储过程名,
DBMS_SQLTUNE.CREATE_TUNING_TASK会报错:ORA-13754: SQL statement is required - 即使过程里只有一条
SELECT,你也得把那条 SQL 单独拎出来分析,不能“整块提交” - PL/SQL 引擎本身的开销(如变量赋值、IF 判断)在 19c 中极低,瓶颈几乎总在 SQL 执行层
怎样正确提取 PL/SQL 中的慢 SQL 交给 SQL Tuning Advisor
关键不是“怎么包进 PL/SQL”,而是“怎么从 PL/SQL 运行痕迹里揪出真凶”。常用路径有三条:
- 查
V$SQL:在 PL/SQL 执行后立即运行SELECT sql_id, sql_text, elapsed_time, executions FROM v$sql WHERE sql_text LIKE '%your_table_name%' AND last_active_time > SYSDATE - 1/24,挑elapsed_time/executions高的sql_id - 用 AWR 报告定位:生成最近一小时 AWR 报告(
awrrpt.sql),翻到 “SQL ordered by Elapsed Time” 章节,找被该 PL/SQL 频繁调用的 SQL - 启用 SQL Trace:在会话中执行
ALTER SESSION SET sql_trace = TRUE,再运行 PL/SQL,最后用tkprof解析 trace 文件,直接看到每条 SQL 的物理读、执行次数和等待事件
对 PL/SQL 中 SQL 调优后的落地要点
拿到 SQL Tuning Advisor 的建议(比如加索引、改写为 EXISTS、加 hint),别急着改代码——要验证是否真生效,尤其在 RAC 或绑定变量场景下:
- 加索引后,立刻用
EXPLAIN PLAN FOR ...; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);确认走了新索引,而不是仍走全表扫描 - 如果建议加
/*+ INDEX(t idx_col) */,别直接硬编码进 PL/SQL;优先用 SPM 捕获基线:DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(注意:必须跨 RAC 所有节点执行,或改用LOAD_PLANS_FROM_SQLSET) - 若原 SQL 含绑定变量,且 Advisor 建议“收集直方图”,那就得去跑
DBMS_STATS.GATHER_TABLE_STATS并显式指定method_opt => 'FOR COLUMNS SIZE 254 status_code',不能依赖AUTO
容易被忽略的 PL/SQL 层级干扰项
即便 SQL 执行计划完美,PL/SQL 写法不当仍会拖慢整体响应——这些点不在 Advisor 范围内,但必须人工检查:
- 游标循环里嵌
SELECT:例如FOR r IN (SELECT id FROM orders) LOOP SELECT amt FROM line_items WHERE order_id = r.id; END LOOP;→ 必须改为单次关联查询,或用BULK COLLECT+ 关联集合 - 重复解析同一动态 SQL:用
EXECUTE IMMEDIATE时没复用语句句柄,导致高频硬解析 → 改用DBMS_SQL接口缓存c句柄 - 过度使用
DBMS_OUTPUT.PUT_LINE:在批量处理中每行都打日志,I/O 累积成瓶颈 → 生产环境应关闭或仅在异常分支输出


















