使用dbms_shared_pool.purge清除共享池中的SQL执行计划

本文介绍如何在Oracle数据库中精确清除指定SQL语句的执行计划,避免使用过程中因旧计划导致的问题。通过使用sys账户调用dbms_shared_pool.purge存储过程,并提供具体步骤及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有时候,需要测试SQL的性能,但是运行过的SQL会在共享池中生成执行计划,如何精确的清除SQL语句执行计划?

注意:在11g中,好像只有sys和system两个账户可以使用这个存储过程。

执行SQL语句

select count(1) from abc ;
显示结果:

查询共享池中该SQL语句的执行计划:

select SQL_TEXT,sql_id, address, hash_value, executions, loads, parse_calls, invalidations  
from v$sqlarea  V
where v.SQL_TEXT like '%select count(*) from abc%';
显示执行结果:

执行dbms_shared_pool.purge清除执行计划:

call sys.dbms_shared_pool.purge('BE988DB4,1573609778','c')
执行成功!!!
再次查看该语句的执行计划是否存在,显示结果:


    过程PURGE的第一个参数为V$SQLAREA中用逗号分隔的ADDRESS列HASH_VALUE列的值,第二个参数'C'表示PURGE的对象是CURSOR(游标),不过实际上这里可以使用除了P(PROCEDURE/FUNCTION/PACKAGE)、T(TYPE)、R(TRIGGER)和Q(SEQUENCE)的任何值。
    使用这种方法,就可以精确的将一个SQL从共享池中删除,从而使得Oracle为这个SQL重新生成执行计划。这种方法只针对单个SQL语句,使得解决问题的同时不会造成任何的误伤。
    不过需要注意一点,在10.2.0.4中,虽然PURGE过程已经存在,但是要使这个过程可以真正的生效,还必须设置一个EVENT:

SQL> alter system set event = '5614566 trace name context forever' scope = spfile;
System altered.
    设置EVENT后需要重启,DBMS_SHARED_POOL的PURGE才可以生效。也就是说,除非提前进行过设置,否则这个PURGE的功能对于一个产品环境而言,必须在10.2.0.5以上版本才可以使用。








<think>我们正在解决如何识别导致共享池碎片化的具体SQL语句的问题。根据之前的讨论,共享池碎片化的主要原因之一是高版本游标(即同一条SQL语句有多个子游标),这通常是由于没有使用绑定变量导致SQL文本不同(即使语义相同),从而每个SQL文本都被视为不同的语句而分别生成执行计划。此外,一些大对象(如大包、过程等)也可能导致碎片。步骤:1.首先,我们可以查询v$sqlarea视图,找出那些有高版本游标的SQL语句(version_count高)。这些SQL语句可能是碎片的主要来源。2.其次,我们可以检查v$sql_shared_cursor视图,了解为什么同一条SQL会有多个子游标。原因可能包括:绑定变量长度不匹配(BIND_MISMATCH)、字符集不同(CHARSET_MISMATCH)等。3.另外,我们还可以通过v$sgastatv$kglheap视图来定位哪些对象(如SQL语句、包、过程等)导致了大量的内存碎片。具体操作:1.查找高版本游标的SQL:```sqlSELECTsql_id,sql_text,version_count,executionsFROMv$sqlareaWHEREversion_count>20--阈值可以根据实际情况调整ORDERBYversion_countDESC;```2.对于某个高版本游标的SQL,进一步查看其子游标的不同原因:```sqlSELECT*FROMv$sql_shared_cursorWHEREsql_id='&sql_id';--替换为实际的sql_id```这个视图会显示每个子游标(通过child_number区分)的不匹配原因(每列代表一种原因,值为'Y'表示该原因导致不能共享)。3.检查哪些对象占用了大量的共享池内存且产生了多个内存块(碎片):```sqlSELECTkglnaobjASobject_name,kglnahshAShash_value,COUNT(*)ASchunk_count,SUM(kglhdsiz)AStotal_sizeFROMx$kglheap--注意:x$kglheap是底层表,需要DBA权限WHEREkglhdnsp=0--0表示SQLAREAGROUPBYkglnaobj,kglnahshHAVINGCOUNT(*)>10--内存块数量超过10个,可能表示碎片化ORDERBYtotal_sizeDESC;```注意:x$kglheap是内部表,访问可能需要权限,并且不同Oracle版本可能有差异。4.另一种方法是检查共享池中空闲内存的碎片情况,并关联到相邻的内存块所属的对象(但这种方法较为复杂):```sql--以下查询尝试找出与空闲内存相邻的内存块所属的对象(这些对象释放后可能导致碎片)SELECTk.globals_nameASobject_name,COUNT(*)ASadjacent_free_chunksFROM(SELECTkglhdadr,kglhdpar,kglhdnsp,kglnaobj,kglnahshFROMx$kglheapWHEREkglhdnspIN(0,1,2,3)--0:SQL,1:TABLE,2:CLUSTER,3:OBJECT)k,(SELECTaddr,sizeFROMv$sgastatWHEREpool='sharedpool'ANDname='freememory')fWHEREk.kglhdadrBETWEENf.addrANDf.addr+f.size--对象内存块与空闲块相邻(或包含在空闲块中?)ORf.addrBETWEENk.kglhdadrANDk.kglhdadr+k.sizeGROUPBYk.globals_nameORDERBYadjacent_free_chunksDESC;```注意:上述查询可能需要调整,因为v$sgastat中freememory的记录可能是多个不连续的内存块,而x$kglheap中的内存块地址也是分散的。这个查询只是提供一个思路,实际可能需要更复杂的逻辑。5.另外,我们还可以使用Oracle提供的诊断脚本(如由OracleSupport提供的脚本)来更精确地分析共享池碎片,例如:hcheck.sql、prvtshpl.sql等。由于共享池碎片问题的复杂性,通常我们首先关注高版本游标的SQL,因为它们是最常见的碎片来源。如果找到了导致碎片的SQL,解决方法通常是:-在应用程序中使用绑定变量。-对于不能使用绑定变量的情况,可以考虑设置cursor_sharing参数(FORCE或SIMILAR,但注意Oracle12c开始SIMILAR已被废弃,推荐使用FORCE或EXACT)。-定期清理共享池(ALTERSYSTEMFLUSHSHARED_POOL)作为临时措施,但这不是长久之计。参考引用:-在引用[2]中提到,Sharedpool缓存SQL执行计划,如果同一条SQL有多个版本,就会占用多个内存块,导致碎片。-引用[3]中提到了查询v$sgastat来查看共享池的空闲内存,我们可以通过这个视图监控碎片情况(大量的freememory小内存块)。因此,定位具体SQL的重点是分析高版本游标内存对象分布。注意:在生产环境中执行这些诊断查询可能会对性能有一定影响,特别是访问x$表时,建议在非高峰时段进行。生成相关问题:1.如何解决Oracle共享池中的高版本游标问题?2.使用绑定变量有哪些最佳实践?3.除了SQL语句,还有哪些对象会导致共享池碎片?4.如何监控Oracle共享池的内存使用情况?</think>### 识别导致Oracle共享池碎片化的具体SQL语句 #### 诊断步骤 1. **定位高版本游标(主要碎片来源)** 同一条SQL因未使用绑定变量产生多个子游标版本: ```sql SELECT sql_id, sql_text, version_count AS 版本数, executions AS 执行次数, ROUND(sharable_mem/1024, 2) AS 内存_KB FROM v$sqlarea WHERE version_count > 20 -- 高版本阈值 ORDER BY version_count DESC; ``` - **关键指标**:`版本数 > 20`表示严重碎片风险[^2] 2. **分析子游标不共享原因** 查看具体未共享的原因(如绑定变量类型不匹配): ```sql SELECT child_number, bind_mismatch, -- 绑定变量不匹配 optimizer_mismatch -- 优化器模式不同 FROM v$sql_shared_cursor WHERE sql_id = '&目标SQL_ID'; -- 替换为高版本SQL的ID ``` - `Y`表示该原因导致子游标无法共享 3. **检查大对象内存分配** 查找占用连续内存的大对象: ```sql SELECT kglnaobj AS 对象名, COUNT(*) AS 内存块数, SUM(kglhdsiz)/1024 AS 总大小_KB FROM x$kglheap -- 需要DBA权限 WHERE kglhdnsp = 0 -- 0=SQL AREA GROUP BY kglnaobj HAVING COUNT(*) > 5 -- 碎片化阈值 ORDER BY 总大小_KB DESC; ``` 4. **监控共享池保留区失败** 检测因碎片导致的大内存分配失败: ```sql SELECT request_failures AS 分配失败次数, request_misses AS 缓存未命中, last_failure_size AS 最后失败大小 FROM v$shared_pool_reserved WHERE request_failures > 0; ``` #### 关键分析工具 | 视图名称 | 核心作用 | 关键字段 | |----------------------|--------------------------|-----------------------| | `v$sqlarea` | 识别高版本SQL | `version_count` | | `v$sql_shared_cursor`| 分析子游标不共享原因 | `bind_mismatch` | | `x$kglheap` | 查看内存块分布 | `kglhdsiz`, `kglhdnsp`| | `v$shared_pool_reserved`| 监控大内存分配失败 | `request_failures` | #### 解决方案 1. **绑定变量优化** ```sql -- 查找未使用绑定变量的SQL SELECT sql_fulltext FROM v$sql WHERE executions=1 AND sql_text LIKE '%WHERE department_id = %'; -- 替换实际列名 ``` 2. **强制游标共享** ```sql ALTER SYSTEM SET cursor_sharing = FORCE; -- 慎用,可能影响性能 ``` 3. **清理特定游标** ```sql -- 使用DBMS_SHARED_POOL清除碎片对象 EXEC DBMS_SHARED_POOL.PURGE('&ADDRESS, &HASH_VALUE', 'C'); ``` > **注意**:分析`x$kglheap`需要DBA权限,建议在测试环境验证后再在生产环境执行。根本解决方案是优化应用使用绑定变量[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值