Fine Grained Dependencies

talio發表於2014-03-26

Fine Grained Dependencies是oracle 11g引入的一個新特性.  資料庫中的某些物件之間會存在依賴關係,這些依賴關係可透過檢視all/dba/user_dependencies查詢得到. 在11g之前的版本中, 當記錄這種依賴關係時只能具體到物件級別, 這樣當某個被依賴的物件發生metadata的變化時,依賴於該物件的其他物件就會被置為invalid, 隨後應用在訪問這些失效的物件時就需要重新編譯他們.比如,  檢視V 依賴於表T的列C1, C2和C3 , 如果我們在表V上新增一個新列C4, 則檢視 V就會由於基表T的結構變化而被置為invalidate. 但實際上我們知道,檢視V其實只是依賴於表T的C1,C2和C3列,而表T的新增列並不對檢視的使用構成影響. 11g引入了Fine Grained Dependencies, 資料庫對物件間的依賴關係的描述可以具體到column級, 這樣, 前面例子中的檢視V就不用再被置為invalid了.
如下例:

  1. create table TEST_DEPENDENCY ( text varchar2(20));
  1. create view DEPENDENCY_VW as select text from TEST_DEPENDENCY;
  1. alter table TEST_DEPENDENCY add (doc clob);
  1. select owner,object_type,status from dba_objects where object_name=\'DEPENDENCY_VW\';
  1. OWNER OBJECT_TYPE STATUS
  1. ------------------------------ ------------------- -------
  1. LT_TEST VIEW VALID

關於Fine Grained Dependencies特性的更多介紹和例項可參考metalink文件430725.1.

這個新特性看起來是很好的,但在實際中我們會注意到,還是有些物件會在基表結構發生改變時被置為invalidate, 在我們檢查這些被置為invalid物件的程式碼時並沒有發現會受這種基表操作影響的證據.這是什麼原因造成的呢?

首先,看看11g是如何實現Fine Grained Dependencies這個新特性的:

既然oracle能針對column級的依賴關係來判斷是否需要invalidate一個物件,那麼就必然在資料庫中記錄了這些依賴列資訊. dba_denpendencies檢視的底層表是dependency$:

  1. desc dependency$
  2. Name Null? Type
  3. ---------------------- -------- ----------------------------
  4. D_OBJ# NOT NULL NUMBER
  5. D_TIMESTAMP NOT NULL DATE
  6. ORDER# NOT NULL NUMBER
  7. P_OBJ# NOT NULL NUMBER
  8. P_TIMESTAMP NOT NULL DATE
  9. D_OWNER# NUMBER
  10. PROPERTY NOT NULL NUMBER
  11. D_ATTRS RAW(2000)
  12. D_REASON RAW(2000)

從dependency$表的結構可能,列依賴資訊最有可能記錄在列D_ATTRS或者D_REASON中.

  1. select o.owner#, o.name,p.NAME ref_obj,d.d_timestamp, d.d_attrs,d.d_reason
  2. from dependency$ d, obj$ o, obj$ p
  3. where d.d_obj#=o.obj# and d.p_obj#=p.obj# and p.name=\'TEST_DEPENDENCY\'
  4.     OWNER# NAME              REF_OBJ        D_TIMEST   D_ATTRS                          D_REASON
  5. ---------- --------------- --------------- --------    ------------------------------ ------------------------------
  6.       4030 DEPENDENCY_VW TEST_DEPENDENCY    20140324   0001000002


從查詢結果看來,依賴關係應該是記錄在列D_ATTRS中.

在該測試案例中, DEPENDENCY_VW檢視需要訪問TEST_DEPENDENCY表的列text,為第一個列. D_ATTRS列記錄的資訊為0001000002,該資訊該如何解讀呢?

在以下link中,

http://rwijk.blogspot.co.uk/2008/10/dbadependencycolumns.html

Rob Van Wijk透過測試說明了D_ATTRS列是如何來記錄列reference關係的,大致對應關係如下:

NAME             COLUMN_ID        ATTRS            
--------------- -------------- --------------------
MYPROC1               1        0001000002          
MYPROC2               2        0001000004          
MYPROC3               3        0001000008          
MYPROC4               4        0001000010          
MYPROC5               5        0001000020          
MYPROC6               6        0001000040          
MYPROC7               7        0001000080          
MYPROC8               8        000100000001        
MYPROC9               9        000100000002        
MYPROC10              10       000100000004        
MYPROC11              11       000100000008        
MYPROC12              12       000100000010        
MYPROC13              13       000100000020        
MYPROC14              14       000100000040        
MYPROC15              15       000100000080        
MYPROC16              16       00010000000001      
MYPROC17              17       00010000000002      
MYPROC18              18       00010000000004      
MYPROC19              19       00010000000008      
MYPROC20              20       00010000000010      

前8位字元統一為"00010000",代表的含義不清楚,後面的16進位制格式數字是一種二進位制位表示法,採用逆序排列,對應的位為1時,表示對應的列被引用. 同時,為了方便檢視, Rob還建立了檢視dba_dependency_columns,用於記錄引用列的詳細資訊.

到這裡,仍沒有之前問題的答案:"有些物件會在基表結構發生改變時被置為invalid,而檢查這些被置為invalid物件的程式碼時並沒有發現會受這種基表操作影響的證據".

比如,在我們的系統中, package ROO_API_PKG依賴於表XXX.root的: 


  1. select OWNER,NAME,TYPE from dba_dependencies where REFERENCED_OWNER=\'CORECAT\' and REFERENCED_NAME=\'ROOT\' and owner=\'XXX\';
  2. OWNER NAME TYPE
  3. ------------------------------ ------------------------------ ------------------
  4. XXX ROO_API_PKG PACKAGE BODY
  5. XXX ROO_API_PKG PACKAGE

  6. select o.owner#, o.name,p.NAME ref_obj,d.d_timestamp, d.d_attrs,decode(o.type#,9,\'PACKAGE\',11, \'PACKAGE BODY\')
  7. from dependency$ d, obj$ o, obj$ p
  8. where d.d_obj#=o.obj# and d.p_obj#=p.obj# and p.name=\'ROOT\' and o.name=\'ROO_API_PKG\';
  9.     OWNER# NAME REF_OBJ D_TIMEST
  10. ---------- ------------------------------ ------------------------------ --------
  11. D_ATTRS
  12. ------------------------------------------------------------------------------------------------------------------------
  13. DECODE(O.TYP
  14. ------------
  15.         56 ROO_API_PKG ROOT 20120122
  16. 000100001E0E
  17. PACKAGE
  18.  
  19.         56 ROO_API_PKG ROOT 20140324
  20. 000300001E0E
  21. PACKAGE BODY

D_ATTRS列從第9位開始的值為1E0E,表明第1,2,3,4,9,10,11列被ROO_API_PKG引用。當我們給root表新增新列時,從Fine

Grained Dependencies的資訊和package body的定義來看,是不影響package ROO_API_PKG的訪問的。

  1. alter table XXX.root add (test number);
  2. SQL> select owner,object_type,status from dba_objects where object_name=\\\'ROO_API_PKG\\\';
  3. OWNER OBJECT_TYPE STATUS
  4. ------------------------------ ------------------- -------
  5. XXX PACKAGE VALID
  6. XXX PACKAGE BODY INVALID

但從上面的測試結果來看,package body ROO_API_PKG還是被置為了INVALID。這是為什麼呢?這似乎與fine grained dependencies這個新特性是矛盾的。回頭看看dependency$表中D_ATTRS列的資訊來看,惟一可疑的是這裡package body前8位的值是00030000。而從之前的測試結果來看,這前8位的值一般為00010000,而不是00030000,從現有的資料我們也無從考證00010000代表的含義。考慮到該值的差異,我懷疑當基表發生結構變化時,即使不改變被依賴的列,但若D_ATTRS列的前8位為00030000,則該依賴物件也會被置為INVALID.按照該假設,我又查詢了系統中其他的物件,當D_ATTRS列的前8位為00030000時,也會由於其基表看似無關的結構變化而被置為INVALID。

也就是說,從oracle 11g開始,隨著fine grained dependencies特性的引入,當我們對被依賴物件作metadata改變時,只有被依賴物件具體的列發生了變化,oracle才會將依賴物件置為INVALID,從而提高了可用性。但這一結論也存在例外,那就是若dependency$表D_ATTRS列的前8 位值不是00010000,而是00030000,則很可能意味著oracle對這個物件作了特殊處理,基表的變化還是會引起該物件的invalid。

(以上結論是基於觀察得到的,可能不準確,但在發現違反該結論的案例前,暫且認為它是正確的)。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/27243841/viewspace-1130034/,如需轉載,請註明出處,否則將追究法律責任。

相關文章