1.v$sql和v$sqlarea的區(qū)別
v$sql和v$sqlarea從某種意義上具有父子關(guān)系。即v$sqlarea保存的是父游標(biāo)的sql信息,而v$sql保存的是子游標(biāo)的sql的信息。在v$sqlarea里面有一列VERSION_COUNT字段,其中代表的就是對于此父游標(biāo)的子游標(biāo)的數(shù)量,也就是在v$sql里面的子游標(biāo)的sql記錄的數(shù)量。在v$sql中有一列CHILD_NUMBER字段,表示該字游標(biāo)的編號。可以說v$sqlarea和v$sql是一對多的父子關(guān)系。
2.父游標(biāo)和子游標(biāo)
每種類型的dml語句都需要如下階段:
Create a Cursor 創(chuàng)建游標(biāo)
Parse the Statement 分析語句
Bind Any Variables 綁定變量
Run the Statement 運(yùn)行語句
Close the Cursor 關(guān)閉游標(biāo)
當(dāng)數(shù)據(jù)庫第一次對一條SQL語句進(jìn)行硬解析的時候,會在庫緩存中分配一些內(nèi)存,并將新產(chǎn)生的父游標(biāo)保存進(jìn)去。與父游標(biāo)有關(guān)的關(guān)鍵信息室這個SQL語句的文本,這個時候,會在v$sqlarea里面插入一條記錄。那么,在什么情況下會產(chǎn)生子游標(biāo)呢,當(dāng)數(shù)據(jù)庫又碰到一條完全相同SQL語句,但是語句的執(zhí)行計(jì)劃和執(zhí)行環(huán)境發(fā)生了變化,比如由于綁定變量窺測而產(chǎn)生的不一致的執(zhí)行計(jì)劃,由于SQL的初始化參數(shù)optimizer_mode的不同以及綁定變量分級的情況都會產(chǎn)生子游標(biāo),當(dāng)產(chǎn)生子游標(biāo)的時候,會在v$sql里面插入一條記錄。并且v$sqlarea里的VERSION_COUNT字段的值會加1。
eg:
--多個SQL語句只有在它們的文本完全一致的情況下才能共享一個父游標(biāo),這是最基本的要求。
--窗口1執(zhí)行
sys/SYS>select * from t;
no rows selected
sys/SYS>select * from t;
no rows selected
sys/SYS>SELECT * from t;
no rows selected
--窗口2執(zhí)行
sys/SYS>select hash_value,sql_text,executions from v$sqlarea where sql_text like '%from t';
HASH_VALUE SQL_TEXT EXECUTIONS
---------- ---------------------------------------- ----------
3542409071 SELECT * from t 1
520543201 select * from t 2
可以看到由于SQL文本不同產(chǎn)生了兩個父游標(biāo)。
sys/SYS>select HASH_VALUE,child_number,sql_text from v$sql where sql_text like '%from t';
HASH_VALUE CHILD_NUMBER SQL_TEXT
---------- ------------ ----------------------------------------
520543201 0 select * from t
3542409071 0 SELECT * from t
在v$sql里面也插入了兩條子游標(biāo)的記錄,但是CHILD_NUMBER都是0,其實(shí)對應(yīng)的就是父游標(biāo)。
現(xiàn)在再來看下由于optimizer_mode的不同而產(chǎn)生子游標(biāo)的情況。
--窗口1執(zhí)行
sys/SYS>alter session set optimizer_mode=all_rows;
Session altered.
sys/SYS>select * from tt;
no rows selected
sys/SYS>alter session set optimizer_mode=first_rows_10;
Session altered.
sys/SYS>select * from tt;
no rows selected
--窗口2執(zhí)行
sys/SYS>select hash_value,sql_text,executions,VERSION_COUNT from v$sqlarea where sql_text like '%from tt';
HASH_VALUE SQL_TEXT EXECUTIONS VERSION_COUNT
---------- ---------------------------------------- ---------- -------------
3762890390 select * from tt 2 2
sys/SYS>select HASH_VALUE,child_number,sql_text from v$sql where sql_text like '%from tt';
HASH_VALUE CHILD_NUMBER SQL_TEXT
---------- ------------ ----------------------------------------
3762890390 0 select * from tt
3762890390 1 select * from tt
可以看到,SQL文本是完全相同的,所以兩個子游標(biāo)共享了一個父游標(biāo)。但是由于optimizer_mode的不同,所以生成了2個子游標(biāo)。
如果產(chǎn)生了子游標(biāo),那么說明肯定產(chǎn)生了某種mismatch,那么如何來查看是何種原因產(chǎn)生了mismatch呢?這就要通過v$sql_shared_cursor了。
sys/SYS>select kglhdpar, address,auth_check_mismatch, translation_mismatch,OPTIMIZER_MISMATCH
2 from v$sql_shared_cursor
3 where kglhdpar in
4 ( select address
5 from v$sql
6 where sql_text like '%from tt');
KGLHDPAR ADDRESS A T O
-------- -------- - - -
89BB8948 89BB83CC N N N
89BB8948 89BB5E78 N N Y
可以看到OPTIMIZER_MISMATCH列第二行的值為Y,這說明了正是由于optimizer_mode的不同而產(chǎn)生了子游標(biāo)。
最后,父游標(biāo)和子游標(biāo)的意義何在?其實(shí)一切都是為了共享。以減少再次解析的資源浪費(fèi)。