怎麼找出解析失敗的sql
原創如有錯誤請指出
本文由我和公司同事問心共同測試分析完成。
很多時候我們會有這樣一個誤區,語法錯誤或者物件不存在應該在語法語義檢查這個步驟就結束了,怎麼還會存在共享池裡面呢?帶著這個幾個問題我們做幾個簡單的測試。
我們先了解下什麼是解析失敗的 SQL?
1、SQL語法錯誤
2、訪問的物件不存在
3、沒有許可權
那麼怎麼證明有哪些解析失敗的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
KGLOBHD6 RAW(4|8) Address of heap 6 descriptor
SQL> select * from scott.emp;
SQL> col kglnaobj for a50;
SQL> select kglnaobj,kglnatim,kglhdpar,kglhdadr,KGLOBHD0,KGLOBHD6 from x$kglob where KGLNAOBJ='select * from scott.emp';
KGLNAOBJ KGLNATIM KGLHDPAR KGLHDADR KGLOBHD0 KGLOBHD6
-------------------------------------------------- ------------------- ---------------- ---------------- ---------------- ----------------
select * from scott.emp 2017-07-07 14:54:52 0000000096AE88B0 00000000958B9A40 0000000096AE85D8 000000007713C758
select * from scott.emp 2017-07-07 14:54:52 0000000096AE88B0 0000000096AE88B0 0000000095871858 00
x$kglcursor_child_sqlid (只包含子游標資訊)
SQL> select kglnaobj,kglnatim,kglhdpar,kglhdadr,KGLOBHD0,KGLOBHD6 from x$kglcursor_child_sqlid where KGLNAOBJ='select * from scott.emp';
KGLNAOBJ KGLNATIM KGLHDPAR KGLHDADR KGLOBHD0 KGLOBHD6
-------------------------------------------------- ------------------- ---------------- ---------------- ---------------- ----------------
select * from scott.emp 2017-07-07 14:54:52 0000000096AE88B0 00000000958B9A40 0000000096AE85D8 000000007713C758
0000000096AE88B0 為select * from scott.emp; 父遊標控制程式碼地址,00000000958B9A40為子游標控制程式碼地址
子游標heap 6(KGLOBHD6)的地址為000000007713C758,控制程式碼中儲存的也就是執行計劃相關的資訊。
透過以上測試我們很容易找到sql的父遊標的控制程式碼還有子游標的控制程式碼在記憶體中的地址。
下面做另外一個簡單的測試解析錯誤的SQL是否有父遊標和子游標生成。
SQL> select * from test;
select * from test
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> select kglnaobj,kglnatim,kglhdpar,kglhdadr,KGLOBHD0,KGLOBHD6 from x$kglob where KGLNAOBJ='select * from test';
KGLNAOBJ KGLNATIM KGLHDPAR KGLHDADR KGLOBHD0 KGLOBHD6
-------------------------------------------------- ------------------- ---------------- ---------------- ---------------- ----------------
select * from test 2017-07-07 15:06:28 0000000097DDC190 0000000097F941F8 00 00
select * from test 2017-07-07 15:06:28 0000000097DDC190 0000000097DDC190 000000009E035698 00
SQL> select kglnaobj,kglnatim,kglhdpar,kglhdadr,KGLOBHD0,KGLOBHD6 from x$kglcursor_child_sqlid where KGLNAOBJ='select * from test';
no rows selected
可以看到沒有子游標生成,因為該SQL執行錯誤不會有執行計劃相關資訊。
從x$kglob 也可以查到 kglobhd0、kglobhd6 都為空(NULL)。
在 x$kglcursor_child 檢視也查不到任何資訊的,v$sql v$sqlare 類似的檢視也就查不到解析錯誤的 SQL 了。
關於解析失敗的SQL還是需要獲取latch,其實從上面的測試已經證明了還是要獲取 shared pool 的 latch的,因為生成了父遊標。
透過以上測試說明解析失敗的sql只生成了父遊標,而沒有生成子游標和執行計劃資訊。
也可以用一下sql查出當前資料庫中所有解析失敗的sql
select kglnaobj,kglnatim,kglhdpar,kglhdadr,KGLOBHD0,KGLOBHD6 from x$kglob where kglhdpar<>kglhdadr
and KGLOBHD6='00' and KGLOBHD0='00' order by kglnatim desc;
從整個過程來看即使解析失敗父遊標是需要分配空間的,如果沒有使用繫結變數的情況下需要大量的分配
記憶體空間來儲存這些解析失敗語句的父遊標,它不僅會持有latch:libary cache而且會持有latch:shared
pool.
最後猜測一下:
KGLNAOBJ KGLNATIM KGLHDPAR KGLHDADR KGLOBHD0 KGLOBHD6
-------------------------------------------------- ------------------- ---------------- ---------------- ---------------- ----------------
select * from scott.emp 2017-07-07 14:54:52 0000000096AE88B0 00000000958B9A40 0000000096AE85D8 000000007713C758
SQL> select ksmchptr,ksmchcom,ksmchcls,ksmchsiz from x$ksmsp where KSMCHPAR='0000000096AE85D8';
KSMCHPTR KSMCHCOM KSMCHCLS KSMCHSIZ
---------------- ------------------------------------------------ ------------------------ ----------
000000007713AFD8 KGLH0^31fa0cc recr 4096(chunk 大小)
如上:
KGLHDADR:應該為整個遊標結構體(控制程式碼)的虛擬記憶體地址其地址為00000000958B9A40
KGLHDPAR:為父遊標構體(控制程式碼的)的虛擬記憶體地址其地址為0000000096AE88B0
而父遊標的KGLHDPAR和KGLHDADR相等,子游標KGLHDPAR為父遊標構體(控制程式碼的)的虛擬記憶體地址,KGLHDADR為自己的
遊標構體(控制程式碼的)的虛擬記憶體地址
在這個結構體中有一根指標指向void* p 指向heap 0 ds描述符的記憶體空間,虛擬記憶體地址為0000000096AE85D8
ds描述符:應該也是一個結構體其中又有一根指標void* p 指向heap 0實際的虛擬記憶體地址為000000007713AFD8
那麼heap0實際的地址為000000007713AFD8
比如:
struct ds
{
KSMCHCOM;
KSMCHCLS;
KSMCHSIZ;
.........
void* p;
}
如果進行dump可以確實可以看到這根指標儲存確實儲存在記憶體中
作者微信:
本文由我和公司同事問心共同測試分析完成。
很多時候我們會有這樣一個誤區,語法錯誤或者物件不存在應該在語法語義檢查這個步驟就結束了,怎麼還會存在共享池裡面呢?帶著這個幾個問題我們做幾個簡單的測試。
我們先了解下什麼是解析失敗的 SQL?
1、SQL語法錯誤
2、訪問的物件不存在
3、沒有許可權
那麼怎麼證明有哪些解析失敗的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
KGLOBHD6 RAW(4|8) Address of heap 6 descriptor
SQL> select * from scott.emp;
SQL> col kglnaobj for a50;
SQL> select kglnaobj,kglnatim,kglhdpar,kglhdadr,KGLOBHD0,KGLOBHD6 from x$kglob where KGLNAOBJ='select * from scott.emp';
KGLNAOBJ KGLNATIM KGLHDPAR KGLHDADR KGLOBHD0 KGLOBHD6
-------------------------------------------------- ------------------- ---------------- ---------------- ---------------- ----------------
select * from scott.emp 2017-07-07 14:54:52 0000000096AE88B0 00000000958B9A40 0000000096AE85D8 000000007713C758
select * from scott.emp 2017-07-07 14:54:52 0000000096AE88B0 0000000096AE88B0 0000000095871858 00
x$kglcursor_child_sqlid (只包含子游標資訊)
SQL> select kglnaobj,kglnatim,kglhdpar,kglhdadr,KGLOBHD0,KGLOBHD6 from x$kglcursor_child_sqlid where KGLNAOBJ='select * from scott.emp';
KGLNAOBJ KGLNATIM KGLHDPAR KGLHDADR KGLOBHD0 KGLOBHD6
-------------------------------------------------- ------------------- ---------------- ---------------- ---------------- ----------------
select * from scott.emp 2017-07-07 14:54:52 0000000096AE88B0 00000000958B9A40 0000000096AE85D8 000000007713C758
0000000096AE88B0 為select * from scott.emp; 父遊標控制程式碼地址,00000000958B9A40為子游標控制程式碼地址
子游標heap 6(KGLOBHD6)的地址為000000007713C758,控制程式碼中儲存的也就是執行計劃相關的資訊。
透過以上測試我們很容易找到sql的父遊標的控制程式碼還有子游標的控制程式碼在記憶體中的地址。
下面做另外一個簡單的測試解析錯誤的SQL是否有父遊標和子游標生成。
SQL> select * from test;
select * from test
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> select kglnaobj,kglnatim,kglhdpar,kglhdadr,KGLOBHD0,KGLOBHD6 from x$kglob where KGLNAOBJ='select * from test';
KGLNAOBJ KGLNATIM KGLHDPAR KGLHDADR KGLOBHD0 KGLOBHD6
-------------------------------------------------- ------------------- ---------------- ---------------- ---------------- ----------------
select * from test 2017-07-07 15:06:28 0000000097DDC190 0000000097F941F8 00 00
select * from test 2017-07-07 15:06:28 0000000097DDC190 0000000097DDC190 000000009E035698 00
SQL> select kglnaobj,kglnatim,kglhdpar,kglhdadr,KGLOBHD0,KGLOBHD6 from x$kglcursor_child_sqlid where KGLNAOBJ='select * from test';
no rows selected
可以看到沒有子游標生成,因為該SQL執行錯誤不會有執行計劃相關資訊。
從x$kglob 也可以查到 kglobhd0、kglobhd6 都為空(NULL)。
在 x$kglcursor_child 檢視也查不到任何資訊的,v$sql v$sqlare 類似的檢視也就查不到解析錯誤的 SQL 了。
關於解析失敗的SQL還是需要獲取latch,其實從上面的測試已經證明了還是要獲取 shared pool 的 latch的,因為生成了父遊標。
透過以上測試說明解析失敗的sql只生成了父遊標,而沒有生成子游標和執行計劃資訊。
也可以用一下sql查出當前資料庫中所有解析失敗的sql
select kglnaobj,kglnatim,kglhdpar,kglhdadr,KGLOBHD0,KGLOBHD6 from x$kglob where kglhdpar<>kglhdadr
and KGLOBHD6='00' and KGLOBHD0='00' order by kglnatim desc;
從整個過程來看即使解析失敗父遊標是需要分配空間的,如果沒有使用繫結變數的情況下需要大量的分配
記憶體空間來儲存這些解析失敗語句的父遊標,它不僅會持有latch:libary cache而且會持有latch:shared
pool.
最後猜測一下:
KGLNAOBJ KGLNATIM KGLHDPAR KGLHDADR KGLOBHD0 KGLOBHD6
-------------------------------------------------- ------------------- ---------------- ---------------- ---------------- ----------------
select * from scott.emp 2017-07-07 14:54:52 0000000096AE88B0 00000000958B9A40 0000000096AE85D8 000000007713C758
SQL> select ksmchptr,ksmchcom,ksmchcls,ksmchsiz from x$ksmsp where KSMCHPAR='0000000096AE85D8';
KSMCHPTR KSMCHCOM KSMCHCLS KSMCHSIZ
---------------- ------------------------------------------------ ------------------------ ----------
000000007713AFD8 KGLH0^31fa0cc recr 4096(chunk 大小)
如上:
KGLHDADR:應該為整個遊標結構體(控制程式碼)的虛擬記憶體地址其地址為00000000958B9A40
KGLHDPAR:為父遊標構體(控制程式碼的)的虛擬記憶體地址其地址為0000000096AE88B0
而父遊標的KGLHDPAR和KGLHDADR相等,子游標KGLHDPAR為父遊標構體(控制程式碼的)的虛擬記憶體地址,KGLHDADR為自己的
遊標構體(控制程式碼的)的虛擬記憶體地址
在這個結構體中有一根指標指向void* p 指向heap 0 ds描述符的記憶體空間,虛擬記憶體地址為0000000096AE85D8
ds描述符:應該也是一個結構體其中又有一根指標void* p 指向heap 0實際的虛擬記憶體地址為000000007713AFD8
那麼heap0實際的地址為000000007713AFD8
比如:
struct ds
{
KSMCHCOM;
KSMCHCLS;
KSMCHSIZ;
.........
void* p;
}
如果進行dump可以確實可以看到這根指標儲存確實儲存在記憶體中
作者微信:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28211342/viewspace-2141803/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- DNS解析失敗了怎麼辦DNS
- 53、快速找出不同【ctrl+】,失敗
- mysql匯入sql檔案過大失敗怎麼辦MySql
- 深入解析:由SQL解析失敗看開發與DBA的效能之爭SQL
- postgresql登入失敗怎麼辦SQL
- 邦芒解析:怎樣面對應聘失敗
- 安卓一鍵root失敗怎麼辦安卓
- windows10更新失敗怎麼辦_win10系統為什麼更新失敗WindowsWin10
- IT創業失敗案例解析4:一家失敗的招聘網站創業網站
- python中pip更新失敗怎麼辦Python
- Windows延緩寫入失敗怎麼辦?Windows
- 顯示卡驅動安裝失敗怎麼辦?
- 寶塔皮膚啟動失敗怎麼回事
- win10升級老失敗的解決方法_win10更新失敗怎麼辦Win10
- windows延緩寫入失敗怎麼辦 延緩寫入失敗的解決辦法Windows
- Oracle中的遊標、硬解析、軟解析、軟軟解析、解析失敗Oracle
- python用install失敗怎麼解決Python
- python tarfile解壓失敗怎麼解決Python
- jmap執行失敗了,怎麼獲取heapdump?
- win8.1update安裝失敗怎麼辦?
- 網站資料庫配置失敗怎麼辦網站資料庫
- CF連線伺服器失敗怎麼回事 cf連線失敗解決辦法伺服器
- PbootCMS出現登入失敗,表單提交校驗失敗等情況怎麼辦?boot
- TP 框架解析 JSON 失敗原因框架JSON
- SQL Server資料庫怎麼找出一個表包含的頁資訊(Page)SQLServer資料庫
- pycharm自動安裝模組失敗了怎麼辦PyCharm
- yum安裝mongodb啟動失敗怎麼解決MongoDB
- Win8應用安裝失敗怎麼辦
- 帝國cms恢復資料失敗怎麼辦
- 網站資料庫連線失敗怎麼辦網站資料庫
- 帝國cms恢復資料失敗怎麼回事
- SQL登入失敗注意事項SQL
- Java的快速失敗和安全失敗Java
- 找出沒有繫結變數的引發硬解析的SQL變數SQL
- windows10系統更新cf失敗怎麼解決Windows
- 織夢cms連線資料庫失敗怎麼辦資料庫
- 網站連結資料庫失敗怎麼解決網站資料庫
- 網站程式連線資料庫失敗怎麼辦?網站資料庫