VPD (Virtual Private Database) = 細粒度訪問控制 (FGAC) = 行級安全 (RLS)。通過策略函數動態在查詢上附加 WHERE 謂詞,實現「同表不同視圖」。
| 類型常量 | 重新求值觸發條件 | 典型場景 | 性能 |
|---|---|---|---|
| DBMS_RLS.DYNAMIC | 每行、每次查詢 | 謂詞極度動態 (如基於行屬性計算) | ★ |
| DBMS_RLS.CONTEXT_SENSITIVE | 會話上下文屬性變化 | 謂詞依賴 SYS_CONTEXT,會話內穩定 | ★★★★ |
| DBMS_RLS.SHARED_CONTEXT_SENSITIVE | 跨會話共享上下文變化 | 多租戶 SaaS,租戶上下文共享 | ★★★★★ |
| DBMS_RLS.STATIC | 僅首次 (SGA 緩存謂詞) | 謂詞由登錄用戶完全決定,會話不變 | ★★★★★★ |
| DBMS_RLS.SHARED_STATIC | 跨會話共享 SGA 緩存 | 報表固定過濾、多用戶同謂詞 | ★★★★★★★ |
CREATE OR REPLACE FUNCTION vpd_dyn (p_schema VARCHAR2, p_obj VARCHAR2)
RETURN VARCHAR2 IS
BEGIN
RETURN 'am_name = ''' || SYS_CONTEXT('USERENV','SESSION_USER') || '''';
END;
/
BEGIN
DBMS_RLS.ADD_POLICY(
object_schema => 'SCOTT', object_name => 'ACCOUNTS',
policy_name => 'DYN_ACCT', function_schema => 'SEC_ADMIN',
policy_function => 'VPD_DYN', policy_type => DBMS_RLS.DYNAMIC
);
END;
/
-- 應用上下文
CREATE OR REPLACE CONTEXT vpd_ctx USING pkg_vpd_ctx;
-- 策略函數:謂詞前綴固定,數值取自上下文
CREATE OR REPLACE FUNCTION vpd_ctx_sens (p_schema VARCHAR2, p_obj VARCHAR2)
RETURN VARCHAR2 IS
BEGIN
RETURN 'balance < ' || SYS_CONTEXT('VPD_CTX','MAX_BAL');
END;
/
BEGIN
DBMS_RLS.ADD_POLICY(
policy_name => 'CTX_BAL',
policy_type => DBMS_RLS.CONTEXT_SENSITIVE, -- 關鍵
...
);
END;
/
登錄後設置:DBMS_SESSION.SET_CONTEXT('VPD_CTX','MAX_BAL', 100000);
會話期間 MAX_BAL 不變 → 函數不再執行 → 極高性能。
CREATE OR REPLACE FUNCTION vpd_stat (p_schema VARCHAR2, p_obj VARCHAR2)
RETURN VARCHAR2 IS
BEGIN
RETURN 'cust_name = ' || SYS_CONTEXT('VPD_CTX','CUST_NAME');
END;
/
BEGIN
DBMS_RLS.ADD_POLICY(
policy_type => DBMS_RLS.STATIC, -- 僅求值一次
...
);
END;
/
⚠️ 風險:若會話中 CUST_NAME 變更,謂詞不刷新 → 數據錯誤!
僅用於「用戶登錄後謂詞終身不變」場景 (如固定租戶 ID)。
balance) 必須有索引。SYS_CONTEXT。CONTEXT_SENSITIVE 替代 DYNAMIC。SHARED_CONTEXT_SENSITIVE。DBMS_REDACT 實現列級掩碼 (VPD 行級 + Redact 列級)。ORA-28113: policy predicate has error → 函數返回非法 SQL 片段 (如缺少引號)。DBMS_RLS.ADD_POLICY 的 sec_relevant_cols / sec_relevant_cols_opt 參數。CONTEXT_SENSITIVE,且上下文屬性會話內未變。