淺談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。
LISTENER=
  (DESCRIPTION=
    (ADDRESS_LIST=
      (ADDRESS=(PROTOCOL=ipc)(KEY=ServiceName/SID))
    )
  )
以下述方式進行連接:
conn user/passwd@ServiceName
若只有一個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;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章