天天看點

淺談oracle中SYS_CONTEXT上下文關系以及TCP和IPC兩種連接配接方式

前天維護資料庫,在執行某個的腳本時,發現結果與實際情況有所出入。對該腳本進行檢查,發現其中包含有一條子查詢語句:

SELECT sys_context('userenv','ip_address') from DUAL;

在sqlplus内執行,傳回結果為空。經翻閱資料,發現該語句的作用是傳回一個上下文的參數值。其中sys_context是一個oracle關鍵字,用于查詢一個命名空間(namespace)中某個參數(parameter)的值。Oracle預設建立的命名空間為“userenv”。該命名空間包含以下參數(摘自Docs Oracle ):

ACTION:子產品中的位置辨別(應用程式名),通過DBMS_APPLICATION_INFO包或者OCI設定。

AUDITED_CURSORID:傳回觸發審計的SQL遊标辨別。該參數在高精度審計環境下總是傳回NULL。

AUTHENTICATED_IDENTITY:傳回認證用的辨別。下列清單中各種使用者類型傳回其後的值:

Kerberos認證企業使用者:kerberos主體名

Kerberos認證外部使用者:kerberos主體名;等同于Schema名

SSL認證企業使用者:使用者PKI證書的識别号

SSL認證外部使用者:使用者PKI證書的識别号

密鑰認證企業使用者:昵稱;等同于登陸名

密鑰認證資料庫使用者:資料庫使用者名,等同于Schema名

OS認證外部使用者:外部作業系統使用者名

Radius/DCE認證外部使用者:方案名

攜帶DN代理:OID識别号

攜帶證書代理:客戶的證書識别号

攜帶使用者名代理:客戶若為本地資料庫使用者則為資料庫使用者名,若為企業使用者則傳回昵稱。

以密碼檔案登陸SYSDBA/SYSOPER:登陸名

以作業系統認證登陸SYSDBA/SYSOPER:作業系統使用者名

AUTHENTICATION_DATA:用于認證登入使用者的資料。

AUTHENTICATION_METHOD:認證方式,包括PASSWORD、KERBEROS、SSL、RADIUS、OS、DCE或者NONE。在Password, Kerberos或者SSL認證模式下可用關鍵字IDENTIFICATION_TYPE區分外部使用者和企業使用者。

BG_JOB_ID:若本會話是由Oracle資料庫背景程序建立的,傳回其任務ID;否則傳回NULL。

CLIENT_IDENTIFIER:傳回某應用通過DBMS_SESSION.SET_IDENTIFIER程式、OCI特性OCI_ATTR_CLIENT_IDENTIFIER或者JAVA類Oracle.jdbc.OracleConnection.setClientIdentifier所設定的辨別。該特性用于各類資料庫元件,鑒别認證為同一資料庫使用者的不同輕量級應用使用者。

CLIENT_INFO:傳回最多64位元組的使用者會話資訊,當應用使用到DBMS_APPLICATION_INFO包時該資訊可被儲存下來。

CURRENT_BIND:傳回高精度審計的綁定變量。

CURRENT_SCHEMA:傳回目前Schema中的預設Schema名。該值随着會話中所使用ALTERSESSION SET CURRENT_SCHEMA聲明而改變。

CURRENT_SCHEMAID:本會話所使用的預設Schema辨別。

CURRENT_SQL/CURRENT_SQLn:CURRENT_SQL傳回目前觸發高精度審計事件的SQL前4k個位元組。CURRENT_SQLn特性傳回接下來以4k位元組遞增的序列,n可以是整數1-7。CURRENT_SQL1傳回4k-8k位元組;CURRENT_SQL2傳回4k至8k位元組,以此往下推。該屬性隻能在高精度審記特性的事件處理器中被指定。

CURRENT_SQL_LENGTH:目前觸發高精度審記、行級安全政策功能或事件處理器的SQL聲明長度。僅在功能或者事件處理器内有效。

DB_DOMAIN:由初始化參數DB_DOMAIN所指定的資料庫域。

DB_NAME:由初始化參數DB_NAME所指定的資料庫名。

DB_UNIQUE_NAME:由初始化參數DB_UNIQUE_NAME所指定的資料庫名。

ENTRYID:目前審計項号碼。高精度審記記錄與一般審計記錄共享該審計項辨別序列。該屬性不能用于分布式SQL聲明。在一個标準或高精度審記的審計處理器中才能看到準确的審計項辨別。

ENTERPRISE_IDENTITY:傳回使用者在企業範圍内的辨別:

對于企業使用者: OID識别号。

對于外部使用者:外部辨別,例如Kerberos主體名,Radius和DCE方案名,作業系統使用者名,證書辨析名等。

對于本地使用者和SYSDBA/SYSOPER登陸:NULL。

下列屬性值根據代理方式而有所變化:

對于帶有識别号的代理:客戶的OID識别号。

對于帶有證書的代理:對于外部使用者為客戶證書識别号;全局使用者為OID識别号。

對于帶有使用者名的代理:若客戶為企業使用者則為OID識别号;若客戶為本地資料庫使用者則為NULL。

FG_JOB_ID:若目前會話是由客戶前台程序建立的,傳回任務辨別;否則傳回NULL。

GLOBAL_CONTEXT_MEMORY:傳回在全局通路的情況下SGA中所使用的号碼。

GLOBAL_UID:在企業使用者安全登陸情況下,傳回從Oracle網際網路目錄中全局使用者辨別,其餘的登陸傳回NULL。

HOST:用戶端用于連接配接本伺服器的裝置名稱。

IDENTIFICATION_TYPE:傳回資料庫中建立該使用者Schema的方式。特别指出,其将顯示出CREATE/ALTERUSER文法中的IDENTIFIED字句。下述清單中,對于不同Schema建立的文法傳回其随後的辨別:

密碼辨別: LOCAL

外部辨別: EXTERNAL

全局辨別: GLOBAL SHARED

使用分辨号作為全局辨別: GLOBAL PRIVATE

INSTANCE:本執行個體的執行個體ID數目。

INSTANCE_NAME:執行個體名。

IP_ADDRESS:用戶端用于連接配接本伺服器的裝置IP位址。

ISDBA:若使用者通過作業系統或者密碼檔案的形式通過DBA特權認證,則傳回TURE。

LANG:語言ISO名,是已有參數‘Language’的縮寫。

LANGUAGE:你的會話目前的語言和範圍,随後是資料庫字元集,格式如下:語言_範圍.字元集。

MODULE:由DBMS_APPLICATION_INFO包或者OCI設定的應用名(子產品)。

NETWORK_PROTOCOL:用戶端與伺服器之間用來建立連接配接的連接配接字元串中'PROTOCOL='所指定的協定名。

NLS_CALENDAR:本會話的日程表。

NLS_CURRENCY:本會話的貨币機關。

NLS_DATE_FORMAT:本會話的日期格式。

NLS_DATE_LANGUAGE:用于表示日期的語言。

NLS_SORT:二進制或者語義排序基礎。

NLS_TERRITORY:本會話的範圍。

OS_USER:初始化該資料庫會話的用戶端程序,其作業系統使用者名。

POLICY_INVOKER:行級别的安全政策功能調用者。

PROXY_ENTERPRISE_IDENTITY:當代理使用者為企業使用者時,傳回OID的使用者辨識名(Distinguished Name)。

PROXY_GLOBAL_UID:對于企業使用者安全(EUS)代理使用者,從Oracle英特網目錄中傳回的全局使用者ID。對其他代理使用者傳回NULL。

PROXY_USER:為session_user打開目前會話的資料庫使用者名(代理使用者名)。

PROXY_USERID:為session_user打開目前會話的資料庫使用者ID(代理使用者ID)。

SERVER_HOST:傳回本執行個體所在伺服器的hostname;

SERVICE_NAME:傳回本會話的service_name;

SESSION_USER:對企業使用者而言,傳回該user的schema. 對于其他使用者,傳回通過資料庫認證的該使用者的username。整個會話中該值保持不變。

SESSION_USERID:目前被認證使用者的user ID。

SESSIONID:審計會話辨別。該屬性無法用于分布式SQL聲明。

SID:會話号(與會話辨別不同)。

STATEMENTID:審計聲明辨別。STATEMENTID表示給定會話中被審計的SQL聲明号碼。該特性不能用于分布式SQL聲明。隻有在标準或高精度審計中通過審計處理器才能看到正确的審計聲明辨別。

TERMINAL:目前會話客戶的作業系統辨別。分布式SQL聲明中,該特性傳回本地會話的辨別。在分布式環境中,本特性隻支援遠端SELECT聲明,不支援遠端INSERT、UPDATE或者DELETE操作。(該參數傳回長度随着不同作業系統而改變。)

其中上述語句的傳回值應為用戶端連接配接的IP位址。由于該腳本應在伺服器上執行,是以發現該處應傳回伺服器IP位址,而傳回空值意味着無法擷取該IP位址。事實上,隻要把該語句改為直接填寫的IP位址,則腳本順利通過。

進一步檢查,發現該腳本在登陸資料庫時使用的指令為conn user/passwd。而其它沒有問題的伺服器上使用conn user/passwd@IP進行連接配接。經過上網搜尋,發現兩種登陸形式确實影響了腳本的執行。

使用TCP連接配接可以使程式在本地或遠端連接配接Oracle資料庫。TCP連接配接需要對Listener進行配置,主要參數為伺服器名(需要DNS)或者伺服器IP位址。 

LISTENER= 

  (DESCRIPTION= 

    (ADDRESS_LIST= 

(ADDRESS=(PROTOCOL=tcp)(HOST=ServerName/ServerIP)(PORT=1521)) 

    ) 

  ) 

以下述方式進行連接配接: 

conn user/passwd@OracleServer

使用IPC可以使程式在本地直接連接配接Oracle資料庫,可以與Oracle共享伺服器同時配置。IPC同樣需要Listener進行連接配接。IPC的參數主要為Service Name或者SID。 

      (ADDRESS=(PROTOCOL=ipc)(KEY=ServiceName/SID)) 

若隻有一個Oracle服務開啟,可省略服務名:

conn user/passwd

另外,據Docs Oracle介紹,還有第三種連接配接模式:Bequeath Protocol。這是一種SQL*NET的協定,無需使用Listener,隻能連接配接到本地獨占模式的Oracle資料庫。

結論:

本地使用用戶端連接配接伺服器時,使用IPC,程式之間直接遞交查詢申請和結果回報;相比之下,TCP連接配接需要經過TCP/IP4層封裝解封裝。是以,一般情況下,使用IPC約有7%到8%的性能提升。但這樣由于不經過TCP/IP協定棧的處理,sys_context無法擷取連接配接用戶端的IP位址,進而導緻該腳本的無法執行。

解決方法:不使用

sys_context(‘userenv’,’ip_address’) from dual;

改用

select utl_inaddr.get_host_address from dual;

本文轉自 gole_huang 51CTO部落格,原文連結:http://blog.51cto.com/golehuang/1179281