查V$SESSION确认PLSQL Compile等待PGA分配,再结合V$PGASTAT判断是否触顶或受_pga_max_size限制;若空壳+native编译成功而原语句卡死,即可锁定为解释型编译阶段PGA不足。

查V$SESSION看卡死会话是否在等PGA分配
编译卡住但没报错,第一反应不是代码写错了,而是资源卡住了。直接查 V$SESSION,重点筛出状态为 WAITING 且模块是 PLSQL Compile 的会话:
SELECT SID, SERIAL#, STATUS, EVENT, SQL_ID, BLOCKING_SESSION FROM V$SESSION WHERE MODULE = 'PLSQL Compile' AND STATUS = 'WAITING';
如果 EVENT 是 PGA memory allocation 或 memory manager 类似字样,基本就坐实了PGA不足;若显示 enq: KO - fast object checkpoint 或 latch: shared pool,那问题可能在共享池或对象争用,得另查。
用V$SQLAREA定位编译耗时最长的语句
PL/SQL编译过程本身会生成临时SQL(比如解析依赖、校验类型),这些语句会进共享池。查 V$SQLAREA 找执行时间异常长、PARSING_SCHEMA_NAME 是当前用户、且 SQL_TEXT 包含 CREATE OR REPLACE PROCEDURE 或 ALTER PROCEDURE COMPILE 的记录:
SELECT SQL_ID, ELAPSED_TIME, BUFFER_GETS, SQL_TEXT FROM V$SQLAREA WHERE SQL_TEXT LIKE '%CREATE OR REPLACE PROCEDURE%' AND PARSING_SCHEMA_NAME = 'YOUR_SCHEMA' ORDER BY ELAPSED_TIME DESC FETCH FIRST 5 ROWS ONLY;
注意:ELAPSED_TIME 单位是微秒,超过几千万(即10+秒)就值得怀疑;如果同一条语句反复出现高耗时,大概率是编译器反复尝试分配PGA失败后重试。
确认当前PGA配置与实际使用缺口
别只看 pga_aggregate_target 设了多少,要对比实时使用峰值:
- 查当前设置:
SHOW PARAMETER pga_aggregate_target - 查历史峰值:
SELECT NAME, VALUE FROM V$PGASTAT WHERE NAME IN ('aggregate PGA auto target', 'total PGA allocated', 'maximum PGA allocated'); - 若
maximum PGA allocated接近甚至超过pga_aggregate_target,说明已触顶;若还差很多但编译仍卡,可能是单个会话被限流(如_pga_max_size隐式限制)
Oracle 19c 默认 _pga_max_size 是 200MB(非文档参数,慎改),大存储过程里带大量 BULK COLLECT 或嵌套表初始化,很容易撞上这个隐形天花板。
绕过编译阶段内存压力的临时验证法
不想动参数也能快速验证是不是PGA导致卡死:把存储过程拆成“定义+编译”两步,跳过语法检查最耗资源的部分:
CREATE OR REPLACE PROCEDURE my_proc AUTHID DEFINER AS BEGIN NULL; END; —— 先建个空壳,能过
再用 ALTER PROCEDURE my_proc COMPILE PLSQL_CODE_TYPE = NATIVE; —— 改用本地编译(需提前配好native编译环境),它不走常规PL/SQL引擎路径,对PGA压力小得多
如果空壳能建、native编译能过,但原 CREATE OR REPLACE 卡死,基本可锁定是解释型编译阶段的PGA分配失败。这时候再调参才有的放矢。
真正麻烦的是那种依赖链深、又带动态SQL和复杂类型推导的存储过程——编译器要在内存里构建完整的符号表,PGA不够时不会报错,只会无限等待或静默超时。所以查 V$SESSION 和 V$PGASTAT 必须同步做,单看一个容易误判。


















