深入理解父遊標,子游標的概念

531968912發表於2016-09-14

父遊標:儲存HASH值,SQL文字--相同SQL語句,就只有一個父遊標
oracle內部是將SQL文字轉化為ASCII值(大小寫ASCII不同)並進行hash函式的運算
父遊標裡主要包含兩種資訊:sql文字以及最佳化目標。父遊標在第一次開啟時被鎖定,直到其他所有的session都關閉該遊標後才被解鎖。當父遊標被鎖定的時候是不能被交換出librarycache的,只有在解鎖以後才能被交換出library cache。父遊標被交換出記憶體時父遊標對應的所有子游標也被交換出library cache。
我們來執行兩條sql語句
select * from t5 where empno=7900;
select * FROM t5 WHERE empno=7900;

然後我們進行查詢
23:47:02 > select sql_id,sql_text,EXECUTIONS,VERSION_COUNT from v$sqlarea where sql_text like '%empno=7900';

SQL_ID        SQL_TEXT                                              EXECUTIONS VERSION_COUNT
------------- -------------------------------------------------- ------------- -------------
c2b7t2mu9xfub select * from t5 where empno=7900                              1             1
8ujbmb6j5xpc6 select * FROM t5 WHERE empno=7900                              1             1
可以看到雖然只是有大小寫不同 但實際上生成了兩個sql_id,所以sql_id是父遊標的辨別標誌
另外一方面,我們也可以知道,一次父遊標就代表了一次硬解析,而硬解析是我們應該完全避免的方式。為此,我們可以cursor_sharing引數與繫結變數的方式來減少父遊標(即硬解析)的產生
先看當前系統的cursor_sharing
00:01:27 > show parameter cursor_sharing 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
cursor_sharing                       string      EXACT
1)、EXACT:通常來說,exact值是Oracle推薦的,也是預設的,它要求SQL語句在完全相同時才會重用,否則會被重新執行硬解析操作。
2)、SIMILAR:similar是在Oracle認為某條SQL語句的謂詞條件可能會影響到它的執行計劃時,才會被重新分析,否則將重用SQL。
3)、FORCE:force是在任何情況下,無條件重用SQL。
此時我們執行
select * from t5 where empno=7788;
select * from t5 where empno=7900;
我們進行檢視
00:00:40 > select sql_id,sql_text,EXECUTIONS,PARSE_CALLS,LOADS from v$sqlarea where sql_text like 'select * from t5%';

SQL_ID        SQL_TEXT                                              EXECUTIONS   PARSE_CALLS         LOADS
------------- -------------------------------------------------- ------------- ------------- -------------
85v4jvh5yj733 select * from t5 where empno=7788                              1             1             1
c2b7t2mu9xfub select * from t5 where empno=7900                              1             1             1
這裡我們解釋下這些的含義
欄位解釋:
PARSE_CALLS 解析的次數
LOADS       硬解析的次數
EXECUTIONS  執行的次數
現在我們改變系統引數再來進行測試
00:15:25 > alter system set cursor_sharing =force;

System altered.

Elapsed: 00:00:00.05
00:17:13 > show parameter cursor_sharing

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
cursor_sharing                       string      FORCE

00:17:30 > /

SQL_ID        SQL_TEXT                                              EXECUTIONS   PARSE_CALLS         LOADS
------------- -------------------------------------------------- ------------- ------------- -------------
5sfmgma8jwcna select * from t5 where empno=:"SYS_B_0"                        1             1             1
此時oracle會自動的把當前的sql語句改寫為帶繫結變數的sql語句
多進行幾次其他查詢
select * from t5 where empno=7782;
select * from t5 where empno=7499;
00:18:57 > /

SQL_ID        SQL_TEXT                                              EXECUTIONS   PARSE_CALLS         LOADS
------------- -------------------------------------------------- ------------- ------------- -------------
5sfmgma8jwcna select * from t5 where empno=:"SYS_B_0"                        3             3             1
可以看到硬解析不會變化
同樣的我們也可以使用繫結變數進行測試
00:24:25 > var x number;
00:24:32 > exec :x:=7900;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01
00:24:55 > select * from emp where empno=:x;

        EMPNO ENAME      JOB                 MGR HIREDATE                      SAL          COMM        DEPTNO
------------- ---------- --------- ------------- ------------------- ------------- ------------- -------------
         7900 JAMES      CLERK              7698 1981-12-03 00:00:00           950                          30

Elapsed: 00:00:00.00
00:25:14 > exec :x:=7788;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
00:25:56 > select * from emp where empno=:x;

        EMPNO ENAME      JOB                 MGR HIREDATE                      SAL          COMM        DEPTNO
------------- ---------- --------- ------------- ------------------- ------------- ------------- -------------
         7788 SCOTT      ANALYST            7566 1987-04-19 00:00:00          3000                          20
00:22:13 > select sql_id,sql_text,EXECUTIONS,PARSE_CALLS,LOADS from v$sql where sql_text like 'select * from emp where%';

SQL_ID        SQL_TEXT                                              EXECUTIONS   PARSE_CALLS         LOADS
------------- -------------------------------------------------- ------------- ------------- -------------
6r15aucqqz440 select * from emp where empno=:x                               1             1             1

Elapsed: 00:00:00.08
00:25:34 > /

SQL_ID        SQL_TEXT                                              EXECUTIONS   PARSE_CALLS         LOADS
------------- -------------------------------------------------- ------------- ------------- -------------
6r15aucqqz440 select * from emp where empno=:x                               2             2             1
可以看到透過使用繫結變數,可以有效的減少硬解析

子游標
當發生硬解析時,在產生父遊標的同時,則跟隨父遊標會產生相應的子游標,此時V$SQL.CHILD_NUMBER的值為0。
如果存在父遊標,由於不同的執行環境,此時同樣會產生新的子游標,新子游標的CHILD_NUMBER在已有子游標基礎上以1為單位累計。
子游標包括遊標所有相關資訊,如具體的執行計劃、繫結變數,OBJECT和許可權,最佳化器設定等。子游標隨時可以被LRU演算法置換出
library cache,當子游標被置換出library cache時,oracle可以利用父遊標的資訊重新構建出一個子遊標來,這個過程叫reload。
v$sql中中 的每一行表示了一個child cursor,根據hash value和address與parent cursor 關聯。
child cursor有自己的address,即v$sql.child_address。
我們也來看看可能生成子游標的兩種情況
00:17:16 > alter system flush shared_pool;

System altered.

Elapsed: 00:00:02.19
00:30:47 > alter system flush buffer_cache;

System altered.

假設在不同的schema下面有相同的表,我們在不同的schema下面分別執行如下的sql語句
00:38:38 > select * from t6 where empno=7369;

        EMPNO ENAME      JOB                 MGR HIREDATE                      SAL          COMM        DEPTNO
------------- ---------- --------- ------------- ------------------- ------------- ------------- -------------
         7369 SMITH      CLERK              7902 1980-12-17 00:00:00           800                          20
00:38:53 > select * from t6 where empno=7369;

        EMPNO ENAME      JOB                 MGR HIREDATE                      SAL          COMM        DEPTNO
------------- ---------- --------- ------------- ------------------- ------------- ------------- -------------
         7369 SMITH      CLERK              7902 1980-12-17 00:00:00           800                          20

00:37:25 > select sql_id,sql_text,EXECUTIONS,VERSION_COUNT from v$sqlarea where sql_text like 'select * from t6%';

SQL_ID        SQL_TEXT                                              EXECUTIONS VERSION_COUNT
------------- -------------------------------------------------- ------------- -------------
7b2sgq6rbgvpa select * from t6 where empno=7369                              2             2
此時我們看到同一個sql_id存在兩個版本的,我們再來看v$sql中的內容
00:43:36 > /

SQL_ID        SQL_TEXT                                    EXECUTIONS   PARSE_CALLS         LOADS    HASH_VALUE  CHILD_NUMBER
------------- ---------------------------------------- ------------- ------------- ------------- ------------- -------------
7b2sgq6rbgvpa select * from t6 where empno=7369                    1             1             1    2931289770             0
7b2sgq6rbgvpa select * from t6 where empno=7369                    1             1             1    2931289770             1
可以看到存在了兩個子游標
現在我們再來看另外一種情況
00:48:32 > select * from t6 where empno=7654;

        EMPNO ENAME      JOB                 MGR HIREDATE                      SAL          COMM        DEPTNO
------------- ---------- --------- ------------- ------------------- ------------- ------------- -------------
         7654 MARTIN     SALESMAN           7698 1981-09-28 00:00:00          1250          1400            30

Elapsed: 00:00:00.07
00:48:57 > alter session set optimizer_mode=first_rows;

Session altered.

Elapsed: 00:00:00.05
00:49:44 > select * from t6 where empno=7654;

        EMPNO ENAME      JOB                 MGR HIREDATE                      SAL          COMM        DEPTNO
------------- ---------- --------- ------------- ------------------- ------------- ------------- -------------
         7654 MARTIN     SALESMAN           7698 1981-09-28 00:00:00          1250          1400            30
00:43:37 > select sql_id,sql_text,EXECUTIONS,VERSION_COUNT from v$sqlarea where sql_text like 'select * from t6%';

SQL_ID        SQL_TEXT                                    EXECUTIONS VERSION_COUNT
------------- ---------------------------------------- ------------- -------------
2hx8th12xzgw5 select * from t6 where empno=7654                    2             2

Elapsed: 00:00:00.07
00:50:02 > select sql_id,sql_text,EXECUTIONS,PARSE_CALLS,LOADS,HASH_VALUE,CHILD_NUMBER from v$sql where sql_text like 'select * from t6%';

SQL_ID        SQL_TEXT                                    EXECUTIONS   PARSE_CALLS         LOADS    HASH_VALUE  CHILD_NUMBER
------------- ---------------------------------------- ------------- ------------- ------------- ------------- -------------
2hx8th12xzgw5 select * from t6 where empno=7654                    1             1             1    1172291461             0
2hx8th12xzgw5 select * from t6 where empno=7654                    1             1             1    1172291461             1
我們可以看到,在改變系統環境改變的情況下,oracle一樣也可能生成新的子游標

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25462274/viewspace-2124985/,如需轉載,請註明出處,否則將追究法律責任。

相關文章