6、模式對象的依賴
某些對象的定義引用了其他對象,比如視圖和過程引用了表。因此,對象依賴于他們定義使用的對象。這一章描述了模式對象的依賴,以及Oracle如何自動跟蹤和管理這種依賴。
這一章包含下列主題:
u 依賴發(fā)起介紹
u 模式對象依賴解決
u 對象名稱解決
u 共享SQL依賴管理
u 本地和遠程依賴管理
某些類型的模式對象在定義中引用了其他的對象。例如,一個視圖定義為一個引用了表或者其他視圖的查詢。一個過程體包含的SQL可以引用數(shù)據(jù)庫的其他對象。一個在定義中引用其他對象的對象叫做依賴對象,而被引用的對象叫做引用對象。圖6-1 顯示了依賴對象和引用對象的區(qū)別:
圖6-1 可能的依賴和引用模式對象的類型
如果你修改引用對象的定義,根據(jù)修改的類型,依賴對象可能也可能不繼續(xù)起作用。例如,如果你刪除了一個表,依賴刪除表的任何視圖都不可用。
Oracle自動記錄對象之間的依賴,這樣可以降低數(shù)據(jù)庫管理員和用戶管理依賴工作的復(fù)雜性。例如,如果你修改了一個表,但有幾個存儲過程依賴它,Oracle在過程下次被引用時(運行或者重新編譯)自動重新編譯依賴過程。
為管理模式對象之間的依賴性,數(shù)據(jù)庫中的所有對象都有一個狀態(tài):
u 有效(Valid)模式對象是已經(jīng)編譯的對象,可以在引用時立刻使用
u 無效(Invalid)模式對象必須在使用之前編譯:
² 對于過程、函數(shù)和包來說,這意味著編譯模式對象
² 對視圖來說,這意味著視圖必須使用當(dāng)前數(shù)據(jù)字典中的定義重新解析
只有依賴對象可以是無效狀態(tài),表、序列和同義詞總是有效的。
如果視圖、過程、函數(shù)或包是無效狀態(tài),Oracle可能已經(jīng)試圖編譯它們,但是發(fā)生了錯誤。例如,當(dāng)編譯一個視圖,其中的基表可能不存在或者沒有對于基表足夠的權(quán)限。當(dāng)編譯一個包,可能遇到一個PL/SQL或者SQL語法錯誤,或者引用對象沒有足夠的權(quán)限。模式對象遇到這種問題仍然是無效的。
Oracle自動跟蹤數(shù)據(jù)庫中定義的改變并在數(shù)據(jù)字典中記錄相關(guān)對象的合適的狀態(tài)。
狀態(tài)記錄是一個遞歸過程。引用對象狀態(tài)的任何改變不僅改變直接依賴對象的狀態(tài),還影響間接依賴對象的狀態(tài)。
例如,考慮一個直接引用一個視圖的存儲過程。實際上,存儲過程間接的引用視圖的基表。因而,如果你修改了基表的結(jié)構(gòu),視圖就變成無效的了,然后會造成存儲過程的無效。圖6-2 顯示了間接依賴:
圖 6-2 間接依賴
當(dāng)一個模式對象在SQL語句中直接或間接引用一個對象,Oracle根據(jù)需要會檢查SQL語句中顯示指定的對象或其他引用對象的狀態(tài)。Oracle采取的行動依賴于在SQL語句中直接或間接指定的對象狀態(tài):
u 如果每個引用對象都是有效的,那么Oracle會立刻運行SQL語句,不用任何額外的工作。
u 如果引用的視圖或者PL/SQL程序單位(過程、函數(shù)或包)無效,然后Oracle自動嘗試編譯對象:
² 如果一個無效對象能夠成功編譯,然后Oracle就會編譯它們,然后執(zhí)行SQL語句
² 如果一個無效對象不能成功編譯,那么它還是無效的。Oracle返回一個錯誤并回滾失敗的SQL語句。事務(wù)的剩余部分不做改變,可以被用戶提交或者回滾。
注意:無效對象被檢測為無效之后,只有在沒有被替換的情況下,Oracle才會試圖動態(tài)的重新編譯無效對象。這個優(yōu)化減少了不需要的重新編譯。
視圖或者PL/SQL程序單位只有在滿足下列條件下才會編譯,并生效:
u 視圖或程序單位的定義必須是正確的。所有的SQL和PL/SQL語句必須是正確組織的。
u 所有的引用對象必須存在和有希望的結(jié)構(gòu)。例如,如果視圖的查詢定義包含一個列,這個列必須在基表中存在。
u 視圖或程序單位的擁有者必須擁有引用對象的必要的權(quán)限。例如,如果一個過程的SQL語句要插入一行到一個表中,過程的擁有者必須對引用表有INSERT權(quán)限。
視圖和基表
視圖依賴于查詢定義中的基表或引用的視圖。如果查詢定義沒有明確引用的列,例如,SELECT * FROM table,然后查詢定義被展開,保存到數(shù)據(jù)字典的定義包含當(dāng)時引用表的所有的列。
如果視圖的基表或引用視圖被修改、重命名或者刪除,然后視圖就是無效的,但是它的定義和包括引用這個無效視圖的權(quán)限、同義詞、其他對象以及其他視圖仍保存在數(shù)據(jù)字典中。
注意:無論什么時候你創(chuàng)建了表、索引、視圖,然后刪除表,依賴表的所有對象都是無效的,包括視圖、包、包體、函數(shù)和過程等。
視圖使用一個無效視圖自動會導(dǎo)致Oracle動態(tài)編譯這個視圖。替換這個視圖后,視圖可能是有效,也可能是無效的,這跟下列情況有關(guān):
u 視圖查詢定義中引用的基表必須存在。如果視圖的基表重命名或者刪除了,視圖就是無效的,無法使用。引用一個無效視圖會導(dǎo)致引用語句失敗。只有基表重新命名為原始名稱或者重新創(chuàng)立基表視圖才能被編譯。
u 如果基表被修改或者使用同樣列名創(chuàng)建,但是基表中一個或者多個列的數(shù)據(jù)類型改變了,然后大部分依賴視圖可能成功的重新編譯。
u 如果視圖的基表被修改或者使用至少相同系列的列重建,然后視圖可以是有效的。如果基表使用新列重建而且視圖引用的列不再包含在重建表中,視圖是無效的。最后一個相關(guān)情況是在SELECT * FROM table定義的視圖,因為定義在視圖定義時被擴展,并持久的保存在數(shù)據(jù)字典中。
程序單位和引用對象
當(dāng)引用對象修改之后,Oracle自動將程序單位失效。例如,假定一個單獨過程包含多個語句引用了表、視圖、其他的單獨過程、公用包過程。在那種情況下,會發(fā)生:
u 如果引用表被修改,然后依賴過程無效
u 如果引用視圖的基表被修改,視圖和依賴過程都無效
u 如果引用的單獨過程被替換,然后依賴過程無效
u 如果包體的引用被替換,那么依賴過程就不受影響。但是,如果引用包的定制被替代,那么依賴過程就無效了。這是在一種最小化過程和包引用的對象之間依賴的機制。
u 無論何時你創(chuàng)建了一個表、索引、視圖和刪除表,依賴于表的所有對象都失效,包括視圖、包、包體、函數(shù)和過程在內(nèi)。
數(shù)據(jù)倉庫的考慮
某些數(shù)據(jù)倉庫晚上會刪除表的索引來加快事實表的裝載速度。但是基表的索引被刪除,所有依賴視圖都會失效。這意味著其后運行的引用這些視圖的包都無效。
記住無論何時,你創(chuàng)建了表、視圖、然后刪除索引,依賴表的所有的對象都會失效,包括視圖、包、包體、函數(shù)、過程。這保護了可更新關(guān)聯(lián)視圖。
要是的視圖重新生效,使用下列語句之一:
SELECT * FROM vtest;
或者
ALTER VIEW vtest compile;
會話狀態(tài)和引用包
每個引用一個包結(jié)構(gòu)的會話都有自己的包實例、包括任何公用和私用變量的持久性狀態(tài)、游標(biāo)和常量。所有的會話包實例包含的狀態(tài)在會話的實例包無效和重新編譯之后會丟失。
安全認(rèn)證
當(dāng)一個DML對象或系統(tǒng)權(quán)限分配給一個用戶或PUBLIC或回收權(quán)限時,Oracle會注意到,自動將所有擁有者的依賴對象失效。Oracle將依賴對象失效是為了驗證依賴對象的擁有者還擁有所有引用對象的必須權(quán)限。本質(zhì)上說,Oracle注意到那些不需要重新編譯的對象。只有安全認(rèn)證需要確認(rèn),并不是任何對象的結(jié)構(gòu)需要確認(rèn)。這種優(yōu)化降低了不必要的重新編譯,阻止不必要的修改依賴對象的時間戳。
SQL語句中引用的對象名稱按照周期分為幾個部分。下面描述了Oracle如何解析對象名稱:
1、Oracle嘗試在SQL語句中限定第一部分的引用名稱。例如,在hr.employees,hr是第一部分。如果只有一部分,那么這部分就是第一部分。
a. 在當(dāng)前模式下,Oracle搜索名稱符合對象名稱的第一部分的對象。如果沒有找到這樣的對象,然后轉(zhuǎn)向步驟b。
b. Oracle查找公用同義詞來匹配名稱的第一部分。如果沒有找到,然后轉(zhuǎn)向步驟c。
c. Oracle查找一個模式名字匹配對象名字第一部分的模式,如果找到了,然會步驟b,現(xiàn)在使用名稱第二部分在匹配模式中尋找。如果第二部分不能在前面匹配的模式中找到對象,或者沒有第二部分,Oracle會返回一個錯誤。
如果步驟c無法找到模式,那么對象無法匹配,Oracle返回一個錯誤。
2、模式對象已經(jīng)匹配,任何剩余的名字部分都要匹配找到的對象的有效部分。例如,如果hr.employees.department_id是名字,然后hr作為模式匹配,employees匹配表,department_id必須對對應(yīng)列(因為employees是表)。如果employees匹配一個包,那么department_id必須對應(yīng)一個那個包的公用常量、變量、過程或函數(shù)。
因為Oracle解決引用的方式,很可能一個對象依賴于其他不存在的對象。依賴對象使用的引用采取不同的翻譯方式就會是另一個對象,就有可能發(fā)生這種情況。
在模式對象之間的依賴管理之外,Oracle還在共享池中管理每個共享SQL區(qū)域的依賴。如果一個表、視圖、同義詞或者序列被創(chuàng)建、修改或刪除、或者一個過程或包規(guī)范被重新編譯,所有依賴它們的共享SQL區(qū)域都無效。在對應(yīng)于一個無效共享SQL區(qū)域的游標(biāo)的隨后執(zhí)行中,Oracle會重新分析SQL語句來產(chǎn)生新的共享SQL區(qū)域。
依賴跟蹤和完成必要的重新編譯是Oracle自動執(zhí)行的,本地依賴管理指的是Oracle在單獨數(shù)據(jù)庫中對象中管理依賴。例如,一個過程中的語句能夠引用同一個數(shù)據(jù)庫的表。
遠程依賴管理指的是Oracle跨網(wǎng)絡(luò)在一個分布式環(huán)境中管理依賴。例如,一個Oracle表格觸發(fā)器可以依賴數(shù)據(jù)庫中的一個對象。在分布式環(huán)境中,一個本地視圖定義的查詢可以引用遠程表。
Oracle使用數(shù)據(jù)庫內(nèi)部依賴表來管理所有的本地依賴,內(nèi)部依賴表保存了每個模式對象的依賴對象。當(dāng)一個引用對象被修改,Oracle使用依賴表來標(biāo)識依賴對象,這些對象被標(biāo)識為無效。
例如,假設(shè)一個存儲過程UPDATE_SAL引用了表JWARD.employees。如果表的定義被以任何方式修改,每個引用JWARD.employee的對象狀態(tài)都改為INVALID,包括存儲過程UPDATE_SAL。因此,這個過程不能運行 ,直到它被重新編譯狀態(tài)變?yōu)橛行橹?。類似的,?dāng)一個用戶被撤銷了DML權(quán)限,用戶模式下的每個依賴對象都無效。但是,一個由于認(rèn)證被撤銷導(dǎo)致的對象失效只要重新認(rèn)證就可以重新生效,在這種情況下,不需要全部重新編譯。
Oracle還管理應(yīng)用對數(shù)據(jù)庫和分布數(shù)據(jù)庫的依賴。例如,一個Oracle表格應(yīng)用程序可能包含一個觸發(fā)器,觸發(fā)器指向一個表,或者一個本地存儲過程可能調(diào)用在一個分布式數(shù)據(jù)庫環(huán)境中的過程。數(shù)據(jù)庫環(huán)境必須說明這些對象之間的的依賴。Oracle根據(jù)包含對象的不同,使用不同的機制來管理遠程依賴。
本地和遠程數(shù)據(jù)庫過程之間的依賴
在分布式數(shù)據(jù)庫環(huán)境中的存儲過程、函數(shù)、包、觸發(fā)器之間的依賴使用時間戳校驗或簽名校驗。
動態(tài)初始化參數(shù)REMOTE_DEPENDENCIES_MODE指定是否時間戳或簽名管理遠程依賴。
時間戳管理
在時間戳校驗依賴模型中,無論合適一個過程被編譯或者重新編譯,它的時間戳(創(chuàng)建、修改和替代的時間)在數(shù)據(jù)字典中都會保存。時間戳是記錄過程創(chuàng)建、修改和替代的時間。另外,過程的編譯版本包含它引用的每個遠程過程的信息,包括遠程過程的模式、包名稱、過程名稱和時間戳。
當(dāng)使用了一個依賴過程,Oracle將遠程引用過程的當(dāng)前時間戳和編輯時保存的遠程時間戳。依據(jù)這種比較,會發(fā)生兩種情況:
u 如果時間戳匹配,本地和遠程過程不需要編譯,直接運行
u 如果遠程引用過程時間戳不匹配,本地過程無效,調(diào)用環(huán)境返回一個錯誤。此外,所有其他依賴遠程的新時間戳過程的本地其他過程都無效。例如,假設(shè)多個本地過程調(diào)用一個遠程過程,而遠程過程重新編譯了。當(dāng)一個本地過程運行,并注意到遠程過程的不同時間戳,每個依賴遠程進程的本地過程都無效。
在本地過程體的語句中調(diào)用遠程過程時發(fā)生實際時間戳比較。只有在這個時候,時間戳比較才使用分布式數(shù)據(jù)庫的通訊連接。因而,先于無效過程的本地過程的所有語句可以成功運行。無效過程調(diào)用的隨后的語句無法運行。需要重新編譯。
依賴于如何調(diào)用無效過程,在無效過程調(diào)用之前的DML語句需要回滾。如下所示,隨著整個PL/SQL塊改變被回滾,UPDATE結(jié)果也被回滾。
BEGIN
UPDATE table set ...
invalid_proc;
COMMIT;
END;
但是,如下所示,UPDATE結(jié)果是正常的,之后PROC調(diào)用被回滾。
UPDATE table set ...
EXECUTE invalid_proc;
COMMIT;
簽名校驗
Oracle使用簽名來提供遠程依賴的額外能力。簽名能力只影響遠程依賴。本地依賴是不受影響的,因為這種情況下總可能重新編譯。
過程的簽名包含下列項的信息:
u 包、過程或函數(shù)的名稱
u 參數(shù)基本類型
u 參數(shù)樣式(IN、OUT、IN OUT)
注意:只有參數(shù)的類型和樣式是有意義的。參數(shù)的名字不影響簽名。
如果簽名依賴模式起作用了,如果依賴單位包含一個父單位中的一個過程的調(diào)用,并且這個過程的簽名以一種不兼容的模式修改了,對于遠程程序單位的依賴會導(dǎo)致依賴單位的無效。程序單位可以是包、存儲過程、存儲函數(shù)或者觸發(fā)器。
其他遠程模式對象的依賴
Oracle并不管理遠程模式對象的依賴,只管理本地過程到遠程過程的依賴。
例如,假設(shè)本地視圖被創(chuàng)建,定義中的查詢引用了一個遠程表。還假設(shè)本地過程包含的SQL語句引用了同名的遠程表。然后,表的定義被修改。
因此,本地視圖和過程無法生效,即視圖或過程在表被修改之后使用,甚至現(xiàn)在使用視圖或過程還會返回錯誤。在這種情況下,視圖或過程必須手動修改,這樣才不會返回錯誤。在這種情況下,依賴管理的不足會導(dǎo)致不必要的重新編譯依賴對象。
應(yīng)用程序依賴
數(shù)據(jù)庫應(yīng)用程序的代碼可以指向連接數(shù)據(jù)庫引用的對象。例如,OCI和預(yù)編譯應(yīng)用程序可以提交匿名PL/SQL塊。Oracle表格應(yīng)用程序的觸發(fā)器可以指向一個模式對象。
這些應(yīng)用程序依賴它們引用的模式獨享。依賴管理技術(shù)根據(jù)開發(fā)環(huán)境而不同。