在前面的文章,我為大家介紹了如何使用Oracle 10g的虛擬私有數據庫特征(VPD)掩藏某列數據TechRepublic的成員BrooklynPennyPincher建議我寫一篇關於VPD與關系視圖的比較文章。
前面文章中小技巧的任務是假如department_id的值等於60,那麼掩藏報告中的salary和commission_pct列。因為謂詞是一個靜態值,所以一個關系視圖肯定也能夠完成同樣的任務。
列表A顯示了使用選擇器CASE語句(這個語句在Oracle SQL的8i版本有了)比較depatment_id的值與60的關系的視圖,假如相等返回NULL,假如是另外一個值則返回salary。一個類似的CASE語句也可以掩藏commission_pct列的數據。通過只授權訪問視圖而不是基本標(Employees)來保護數據。
但是假如我稍稍改變一下規則,要求掩藏除了用戶本部門內的所有工資。這將會怎樣? 你的第一想法可能是簡單地創建更多的視圖- -每個部門一個- -並且授予每個用戶訪問對應的視圖的權限。有很多理由說明這不是一個好的解決方案,具體如下:
大量的視圖可能增加維護負擔(例如,假如一個改變了,所有其它的可能也需要改變)。新的部門可能要求新的視圖,用戶必須授予訪問許可,當用戶改變所在部門時,這些訪問許可也必須改變。
視圖中實現的查詢可能是靜態值,而不是綁定變量,因此大量同等重要的查詢副本將存儲在共享池中。
應用開發中必須為不同的用戶調用不同的視圖名,這也是復雜性的一個來源。
列表B對前面文章中的VPD策略函數進行了一些修改。取替直接比較部門號60,該示例中使用了SYS_CONTEXT函數來返回用戶部門號(假設這個值在用戶登錄時設定),然後函數為不同的用戶返回一個不同的斷言(WHERE語句)。工資只在滿足斷言條件的行中顯示,假如沒有設定部門號,將返回始終為假的斷言“1==2”,使得整個報告中的所有工資都被掩藏。
更加有利的是調用函數SYS_CONTEXT作為查詢中一個綁定的變量,只有該查詢的一個副本存儲在共享池中來處理所有部門。
也可以使用SYS_CONTEXT函數以同樣的方式構建關系視圖,但是應用中的一個不同的視圖將可能看到所有的數據。VPD方法將會過濾所有對Employees表的訪問,而不管是哪個查詢。
這是這兩種方法的要害區別:視圖設計用來過濾一個應用內的數據,而VPD設計用來答應大量用戶組透明的共享同樣的數據表,每個人只能看到他自己擁有的數據而不管是何應用。CREATE OR REPLACE VIEW masked_salary_view
AS
SELECT first_name, last_name,
CASE department_id
WHEN 60 THEN NULL
ELSE salary
END AS salary,
department_id
FROM employees
/
CREATE OR REPLACE
FUNCTION rls_dept (obj_owner IN VARCHAR2, obj_name IN VARCHAR2)
RETURN VARCHAR2
AS
deptno NUMBER;
predicate VARCHAR2(200);
BEGIN
deptno := SYS_CONTEXT('HR_CONTEXT','DEPT');
IF deptno IS NULL THEN
predicate := '1=2';
ELSE
predicate := 'department_id = 'deptno;
END IF;
RETURN (predicate);
END rls_dept;
/