解决方案
关于SQL失败解释理论:
我们知道:SQL语句必须至少是一个父游标一个子游标存在的,当然生产中很多情况下都是一父多子的情况。
父游标与子游标结构是一样的,区别在于sql解析相关信息存储在父游标对应的heap 0中,而sql的执行计划等信息存储在子游标对应的库缓存对象heap 6内存空间中。另外父游标的 heap 0中存储着子游标的句柄地址。如果解析错误的SQL在共享池中存储的话那么必然要产生一个父游标然后父游标里面存储的有相关的解析信息,但是子游标的?既然解析失败那么就没有产生执行计划。因此,我们可以利用这一点可以找到解析失败的语句。
父游标句柄对地址可以在 x$kglob 视图中查询到,大体上,KGLHDPAR=KGLHDADR 的记录为父游标,而KGLHDPAR<>KGLHDADR为子游标。
X$KGLOB
该视图定义为 [K]ernel[G]eneric [L]ibrary Cache Manager
KGLHDADR RAW(4|8) Address of kglhd for this object
可以看到:
KGLOBHD0 RAW(4|8) Address of heap 0 descriptor —》data#=0 的 heap 地址
KGLOBHD6 RAW(4|8) Address of heap 6 descriptor —》 sql执行计划
1. 简单测试失败的SQL解释:
执行失败SQL语句:
SQL> select * from T1011;
select * from T1011
*
ERROR at line 1:
ORA-00942: table or view does not exist
查看游标信息:
SQL> set linesize 200
SQL> col kglnaobj format a60
SQL> select kglnaobj, kglnatim, kglhdpar, kglhdadr, KGLOBHD0, KGLOBHD6
2 from x$kglob
3 where KGLNAOBJ = 'select * from T1011';
KGLNAOBJ KGLNATIM KGLHDPAR KGLHDADR KGLOBHD0 KGLOBHD6
------------------------------------------------------------ --------- ---------------- ---------------- ---------------- ----------------
select * from T1011 11-OCT-22 0000000089F11C40 0000000087F94718 00 00
select * from T1011 11-OCT-22 0000000089F11C40 0000000089F11C40 0000000089F11B88 00
注意:KGLHDADR=KGLHDPAR的那一行为父游标信息。
SQL> set linesize 200
SQL> col kglnaobj format a60
SQL> select kglnaobj, kglnatim, kglhdpar, kglhdadr, KGLOBHD0, KGLOBHD6
2 from x$kglcursor_child_sqlid
3 where KGLNAOBJ = 'select * from T1011';
no rows selected
可以看到没有子游标生成,因为该SQL执行错误不会有执行计划相关信息。从 x$kglob 也可以查到 kglobhd0、kglobhd6 都为空(NULL)。
在 x$kglcursor_child 视图也查不到任何信息的,v$sql和v$sqlare 类似的视图也就查不到解析错误的 SQL 了。
关于解析失败的SQL还是需要获取latch,其实从上面的测试已经证明了还是要获取 shared pool 的 latch的,因为生成了父游标。
通过以上测试说明解析失败的sql只生成了父游标,而没有生成子游标和执行计划信息。
从整个过程来看即使解析失败父游标是需要分配空间的,如果没有使用绑定变量的情况下需要大量的分配内存空间来保存这些解析失败语句的父游标,它不仅会持有latch:libary cache而且会持有latch:shared pool.
2. 从library_cache导出:
SQL> oradebug setmypid
Statement processed.
SQL> alter session set events 'immediate trace name library_cache level 11';
Session altered.
SQL> oradebug tracefile_name
/oracle/diag/rdbms/oradb11g/oradb11g/trace/oradb11g_ora_13628.trc
3. 从TRC文件中确认信息:
Bucket: #=13645 Mutex=0x92ef6360(0, 9, 0, 6)
LibraryHandle: Address=0x89f11c40 Hash=33c8354d LockMode=0 PinMode=0 LoadLockMode=0 Status=VALD
ObjectName: Name=select * from T1011
FullHashValue=992362e074c76209e88613dc33c8354d Namespace=SQL AREA(00) Type=CURSOR(00) Identifier=868758861 OwnerIdn=0
Statistics: InvalidationCount=1 ExecutionCount=0 LoadCount=2 ActiveLocks=0 TotalLockCount=1 TotalPinCount=1
Counters: BrokenCount=1 RevocablePointer=1 KeepDependency=0 Version=0 BucketInUse=0 HandleInUse=0 HandleReferenceCount=0
Concurrency: DependencyMutex=0x89f11cf0(0, 1, 0, 0) Mutex=0x89f11d80(1159, 32, 0, 6)
Flags=RON/PIN/TIM/PN0/DBN/[10012841]
WaitersLists:
Lock=0x89f11cd0[0x89f11cd0,0x89f11cd0]
Pin=0x89f11cb0[0x89f11cb0,0x89f11cb0]
LoadLock=0x89f11d28[0x89f11d28,0x89f11d28]
Timestamp: Current=10-11-2022 00:00:49
HandleReference: Address=0x89f11e00 Handle=(nil) Flags=[00]
ReferenceList:
Reference: Address=0x881e53c0 Handle=0x87f94428 Flags=ROD[21]
LibraryObject: Address=0x881e70b0 HeapMask=0000-0001-0001-0000 Flags=EXS[0000] Flags2=[0000] PublicFlags=[0000]
DataBlocks:
Block: #='0' name=KGLH0^33c8354d pins=0 Change=NONE
Heap=0x89f11b88 Pointer=0x881e7150 Extent=0x881e7030 Flags=I/-/-/A/-/-
FreedLocation=0 Alloc=2.460938 Size=3.976562 LoadTime=4816909780
ChildTable: size='16'
Child: id='0' Table=0x881e7f60 Reference=0x881e79b8 Handle=0x87f94718
NamespaceDump:
Parent Cursor: sql_id=fj1hmvhtwhdad parent=0x881e7150 maxchild=1 plk=n ppn=n
Address=0x89f11c40 ----》对应于x$kglob的KGLHDPAR!
ObjectName: Name=select * from T1011 ----》 对应执行解释失败的SQL!