ORACLE獲取SQL綁定變量值的方法總結


 

本文總結一下ORACLE數據庫中如何獲取SQL綁定變量值的方法,在SQL優化調優過程中,經常會用到這方面的知識點。在此梳理、總結一下,方面日后查找、翻閱。

 

 

方法1:查詢V$SQL

 

V$SQL視圖中的BIND_DATA字段用來存儲綁定變量的值,但是從這個視圖查詢綁定變量的值,有很大的局限性:

 

    1: 它的記錄頻率受_cursor_bind_capture_interval隱含參數控制,默認值為900,表示每900秒記錄一次綁定值,也就是說在900內,綁定變量值的改變不會反應在這個視圖中。除非你調整隱含參數_cursor_bind_capture_interval

    2: 它記錄的僅僅最后一次捕獲的綁定變量值。

    3 BIND_DATA數據類型為RAW,需要進行轉換。

 

可以使用下面兩種方式來查看綁定變量的值。

COL SQL_ID FOR A14;
COL SQL_TEXT FOR A32;
COL HASH_VALUE FOR 99999999999;
COL BIND_DATA FOR A32;
SELECT SQL_ID          
      ,SQL_TEXT
      ,LITERAL_HASH_VALUE
      ,HASH_VALUE
      ,DBMS_SQLTUNE.EXTRACT_BINDS(BIND_DATA) BIND_DATA
FROM V$SQL
WHERE SQL_TEXT LIKE ''SELECT * FROM TEST%';
 
 
COL SQL_ID FOR A14;
COL SQL_TEXT FOR A32;
COL HASH_VALUE FOR 99999999999;
COL BIND_DATA FOR A32;
SELECT SQL_ID          
      ,SQL_TEXT
      ,LITERAL_HASH_VALUE
      ,HASH_VALUE
      ,DBMS_SQLTUNE.EXTRACT_BIND(BIND_DATA,1).VALUE_STRING BIND_DATA
FROM V$SQL
WHERE SQL_TEXT LIKE 'SELECT * FROM TEST%';

 

如下實驗所示,我們在一個會話中使用綁定變量的查詢SQL語句,然后,我們來嘗試獲取綁定變量的值,如下所示:

 

 

SQL> SHOW USER;
USER is "TEST"
SQL> DESC TEST;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                                 NUMBER(10)
 NAME                                               VARCHAR2(32)
 
SQL> 
SQL> VARIABLE NAME NVARCHAR2(32);
SQL> EXEC :NAME :='KKKK';
 
PL/SQL procedure successfully completed.
 
SQL> SELECT * FROM TEST WHERE NAME=:NAME;
 
no rows selected
 
SQL> 
 
 
 
SQL>SHOW USER;
USER is "SYS"
SQL> COL SQL_ID FOR A14;
SQL> COL SQL_TEXT FOR A32;
SQL> COL HASH_VALUE FOR 99999999999;
SQL> COL BIND_DATA FOR A32;
SQL> SELECT SQL_ID          
  2        ,SQL_TEXT
  3        ,LITERAL_HASH_VALUE
  4        ,HASH_VALUE
  5        ,DBMS_SQLTUNE.EXTRACT_BINDS(BIND_DATA) BIND_DATA
  6  FROM V$SQL
  7  WHERE SQL_TEXT LIKE 'SELECT * FROM TEST%';
 
SQL_ID         SQL_TEXT                         LITERAL_HASH_VALUE   HASH_VALUE BIND_DATA(NAME, POSITION, DUP_PO
-------------- -------------------------------- ------------------ ------------ --------------------------------
0r7m5jyz9ng09  SELECT * FROM TEST WHERE NAME=:N                  0   3197778953 SQL_BIND_SET(SQL_BIND(NULL, 1, N
               AME                                                              ULL, 1, 'NVARCHAR2(128)', 2000,
                                                                                NULL, NULL, 128, '04-SEP-17', 'K
                                                                                KKK', ANYDATA()))
 
 
SQL> COL SQL_ID FOR A14;
SQL> COL SQL_TEXT FOR A32;
SQL> COL HASH_VALUE FOR 99999999999;
SQL> COL BIND_DATA FOR A32;
SQL> SELECT SQL_ID          
  2        ,SQL_TEXT
  3        ,LITERAL_HASH_VALUE
  4        ,HASH_VALUE
  5        ,DBMS_SQLTUNE.EXTRACT_BIND(BIND_DATA,1).VALUE_STRING BIND_DATA
  6  FROM V$SQL
  7  WHERE SQL_TEXT LIKE 'SELECT * FROM TEST%';
 
SQL_ID         SQL_TEXT                         LITERAL_HASH_VALUE   HASH_VALUE BIND_DATA
-------------- -------------------------------- ------------------ ------------ --------------------------------
0r7m5jyz9ng09  SELECT * FROM TEST WHERE NAME=:N                  0   3197778953 KKKK

 

clip_image001

 

 

 

如果此時你給變量NAME賦值為kerry,然后你使用上面SQL語句查詢,你會發現綁定變量的值依然為"KKKK",這個是因為綁定變量何時被捕獲是有一定規律的:

 

1 含有綁定變量的sql語句被硬解析時

 

2 當含有綁定變量的sql語句以軟解析或者軟軟解析方式重復執行時,該SQL語句中的綁定變量的具體輸入值也可能被ORACLE捕獲,只不過默認情況下這種捕獲操作

受隱含參數_cursor_bind_capture_interval影響,默認需要間隔15900秒)分鍾才會做一次

 

 

SQL> exec :NAME :='kerry';

 

PL/SQL procedure successfully completed.

 

SQL> /

 

        ID NAME

---------- --------------------------------

      1000 kerry

 

SQL>

 

 

 

 

方法2:查詢wrh$_sqlstat

 

 

V$SQL中有BIND_DATA字段,當SQL被解析時,就會放到BIND_DATA字段中,最終會被存入wrh$_sqlstat。關於wrh$_sqlstat的介紹如下所示:

 

wrh$_sqlstat contains a history for SQL execution statistics and stores snapshots of v$sql view.

 

 

wrh$_sqlstat中存儲是v$sql的執行統計信息的快照的歷史記錄,那么從這里可以查詢到一些歷史綁定變量的值,但是也有可能v$sql的快照信息沒有被捕獲到(如滿足什么條件才會被捕獲呢?)。如下截圖所示

 

 

 

 

SQL> select dbms_sqltune.extract_bind(bind_data, 1).value_string
  2  from wrh$_sqlstat
  3  where sql_id='0r7m5jyz9ng09';
 
no rows selected

 

clip_image002

 

 

 

 

如上測試所示,這個獲取綁定變量值的方法有一定的缺陷性,有可能V$SQL快照信息沒有被捕獲到,導致wrh$_sqlstat

里面查不到對應的信息。

 

 

 

注意,如果有1個的綁定值,可以使用如下查詢

 

 

select dbms_sqltune.extract_bind(bind_data, 1).value_string   
 
from wrh$_sqlstat
 
where sql_id = '1t2r2p48w4p0g'

 

 

 

如果有2個綁定值,可以使用如下查詢

 

 

select dbms_sqltune.extract_bind(bind_data, 1).value_string||
'
'--'||dbms_sqltune.extract_bind(bind_data, 2).value_string
 
  from wrh$_sqlstat
 
 where sql_id = '1t2r2p48w4p0g'

 

 

如果有多個綁定變量,使用類似下面SQL

 

select dbms_sqltune.extract_bind(bind_data, 1).value_string
     ||'-'|| dbms_sqltune.extract_bind(bind_data, 2).value_string 
     ||'-'|| dbms_sqltune.extract_bind(bind_data, 3).value_string 
     ||'-'|| dbms_sqltune.extract_bind(bind_data, 4).value_string 
     ||'-'|| dbms_sqltune.extract_bind(bind_data, 5).value_string 
     ||'-'|| dbms_sqltune.extract_bind(bind_data, 6).value_string
from wrh$_sqlstat
where sql_id = '1t2r2p48w4p0g'
/

 

 

 

 

 

方法3v$sql_bind_capture

 

 

使用 V$SQL_BIND_CAPTURE獲取綁定變量的值,也有一些限制:

 

1、如果STATISTICS_LEVEL設置成BASIC,那綁定變量的捕捉就會關閉(Bind capture is disabled when the STATISTICS_LEVEL initialization parameter is set to BASIC.

2、默認是900秒捕捉一次綁定變量值,由_cursor_bind_capture_interval參數控制。

3V$SQL_BIND_CAPTURE視圖中記錄的綁定變量只對WHERE條件后面的綁定進行捕獲,這點需要使用的時候注意。

    對於DML操作,V$SQL_BIND_CAPTURE無法獲取綁定變量的值。

 

 

SQL> COL NAME FOR A12;
SQL> COL DATATYPE_STRING FOR A24;
SQL> COL VALUE_STRING FOR A32;
SQL> SELECT NAME, 
  2         DATATYPE_STRING, 
  3         VALUE_STRING, 
  4         MAX_LENGTH, 
  5         LAST_CAPTURED 
  6  FROM   V$SQL_BIND_CAPTURE 
  7  WHERE  SQL_ID = '1t2r2p48W4P0g'; 
 
NAME         DATATYPE_STRING          VALUE_STRING                     MAX_LENGTH LAST_CAPT
------------ ------------------------ -------------------------------- ---------- ---------
:NAME        NVARCHAR2(128)           KD                                    128 04-SEP-17
 
SQL> 

 

 

v$sql_bind_capture視圖,可以查看綁定變量,但是這個視圖不太給力,只能捕獲最后一次記錄的綁定變量值。而且兩次捕獲的間隔也是受隱含參數_cursor_bind_capture_interval控制。默認是900秒后才會重新開始捕獲。在900內,綁定變量值的改變不會反應在這個視圖中。這個跟v$sql獲取變量值是一樣的。

 

 

SQL> EXEC :NAME :='kerry';

 

PL/SQL procedure successfully completed.

 

SQL>/

 

        ID NAME

---------- --------------------------------

      1000 kerry

 

SQL>

 

 

如上所示,我給變量賦予新的值,然后重新執行一次,你執行上面SQL,發現綁定變量的值為kerry了,之前的值KD就無法找到了。所以這個也是這個視圖的一個局限性。(注意,實驗結果結果也有可能是KD,這個取決於實驗的時間間隔與隱含參數_cursor_bind_capture_interval的值有關系)

 

 

clip_image003

 

 

This view can be joined with V$SQLAREA on (HASH_VALUE, ADDRESS) and with V$SQL on (HASH_VALUE, CHILD_ADDRESS).

 

 

 

--
SET PAUSE ON
SET PAUSE 'Press Return to Continue'
SET PAGESIZE 60
SET LINESIZE 300
 
COLUMN sql_text FORMAT A120
COLUMN sql_id FORMAT A13
COLUMN bind_name FORMAT A10
COLUMN bind_value FORMAT A26
 
SELECT
  sql_id,
  t.sql_text sql_text,  
  b.name bind_name,
  b.value_string bind_value
FROM
  v$sql t
JOIN
  v$sql_bind_capture b  using (sql_id)
WHERE
  b.value_string is not null
AND
  sql_id='&sqlid'
/
 
 
SELECT
  b.sql_id,
  t.sql_text sql_text,  
  b.name bind_name,
  b.value_string bind_value
FROM
  v$sql t
JOIN
  v$sql_bind_capture b  on t.hash_value = b.hash_value and t.child_address = b.child_address
WHERE
  b.value_string is not null
AND
  b.sql_id='&sqlid'
/

 

 

 

方法4:查詢視圖DBA_HIST_SQLBIND.

 

 

DBA_HIST_SQLBIND是視圖V$SQL_BIND_CAPTURE歷史快照. 所以從視圖DBA_HIST_SQLBIND能查到多個綁定變量的值。但是這里依然會遇到一個問題,就是有可能歷史快照沒有被捕獲到DBA_HIST_SQLBIND下。如下測試所示:

 

 

 

SELECT SNAP_ID, 
       NAME, 
       POSITION, 
       VALUE_STRING, 
       LAST_CAPTURED, 
       WAS_CAPTURED 
FROM   DBA_HIST_SQLBIND 
WHERE  SQL_ID = '&SQL_ID' 
       AND SNAP_ID = &SNAP_ID; 
 
 
 
 
SELECT SNAP_ID, 
       NAME, 
       POSITION, 
       VALUE_STRING, 
       LAST_CAPTURED, 
       WAS_CAPTURED 
FROM   DBA_HIST_SQLBIND 
WHERE  SQL_ID = '&SQL_ID';

 

 

 

SQL> SELECT SNAP_ID, 
  2         NAME, 
  3         POSITION, 
  4         VALUE_STRING, 
  5         LAST_CAPTURED, 
  6         WAS_CAPTURED 
  7  FROM   DBA_HIST_SQLBIND 
  8  WHERE  SQL_ID = '&SQL_ID';
Enter value for sql_id: 1t2r2p48w4p0g
old   8: WHERE  SQL_ID = '&SQL_ID'
new   8: WHERE  SQL_ID = '1t2r2p48w4p0g'
 
no rows selected
 
SQL> exec dbms_workload_repository.create_snapshot();
 
PL/SQL procedure successfully completed.
 
SQL> SELECT SNAP_ID, 
  2         NAME, 
  3         POSITION, 
  4         VALUE_STRING, 
  5         LAST_CAPTURED, 
  6         WAS_CAPTURED 
FROM   DBA_HIST_SQLBIND 
  7    8  WHERE  SQL_ID = '&SQL_ID';
Enter value for sql_id: 1t2r2p48w4p0g
old   8: WHERE  SQL_ID = '&SQL_ID'
new   8: WHERE  SQL_ID = '1t2r2p48w4p0g'
 
no rows selected
 
SQL> 

 

 

clip_image004

 

 

 

 

方法5dbms_xplan.display_cursor

 

 

 sql_id       指定位於庫緩存執行計划中SQL語句的父游標。默認值為null。當使用默認值時當前會話的最后一條

                SQL語句的執行計划將被返回。 可以通過查詢V$SQL V$SQLAREASQL_ID列來獲得SQL語句的SQL_ID

 

child_number  指定父游標下子游標的序號。即指定被返回執行計划的SQL語句的子游標。默認值為0。如果為null

               則sql_id所指父游標下所有子游標的執行計划都將被返回。

      

  format       控制SQL語句執行計划的輸出部分,即哪些可以顯示哪些不顯示。

 

 

select * from table(dbms_xplan.display_cursor('1t2r2p48w4p0g', 0, 'ADVANCED'));
 
 
-------------------------------------
SELECT * FROM TEST WHERE NAME=:NAME
 
Plan hash value: 1357081020
 
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |       |       |     3 (100)|          |
|*  1 |  TABLE ACCESS FULL| TEST |     1 |    31 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - SEL$1 / TEST@SEL$1
 
Outline Data
-------------
 
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('11.2.0.1')
      DB_VERSION('11.2.0.1')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      FULL(@"SEL$1" "TEST"@"SEL$1")
      END_OUTLINE_DATA
  */
 
Peeked Binds (identified by position):
--------------------------------------
 
   1 - :NAME (VARCHAR2(30), CSID=873): 'KKK'
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - filter("NAME"=:NAME)
 
Column Projection Information (identified by operation id):
-----------------------------------------------------------
 
   1 - "TEST"."ID"[NUMBER,22], "NAME"[VARCHAR2,32]

 

 

方法610046事件捕獲綁定變量

 

 

alter session set events '10046 trace name context forever, level 4'; --level=4 表示啟用SQL_TRACE並捕捉跟蹤文件中的綁定變量。

 

實驗在此略過,其實ORACLE中seq$表更新頻繁的分析案例中已經展示如何使用10046事件捕獲綁定變量的值。另外v$sql,v$sql_bind_capturedba_hist_sqlbind只能捕獲查詢SQL(確切的說,只對WHERE條件后面的綁定變量進行捕獲)的綁定變量,但10046也能捕獲DMLSQL的值

 

 

 

 

 

最后如果需要可以通過alter system set "_cursor_bind_capture_interval"=10; 修改綁定變量捕獲的時間間隔。

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM