你可以也會發現,Oracle 9中的signature(簽名)字段的值與Oracle 8中的值是不同的. 這是由于Oracle這兩個版本之間策略上的最主要的調整就是為了提高存儲概要的重復利用.在Oracle 8中,只有在你的SQL語句與存儲的SQL語句完全匹配(包含空格符/大小寫以及換行符)的時候才可以使用.到Oracle 9之后,這個限制放寬了,只要在去除掉重復的”空字符”并且將文本都轉換成同樣的大小寫之后SQL語句能夠匹配就可以使用存儲概要了.例如,下面的兩條 SQL語句將使用同一個存儲概要.
select * from t1 where id = 5;
SELECT *
FROM T1
WHERE ID = 5;
策略上的這個調整導致了第一次創建這個執行計劃的SQL語句的簽名的調整;如果你的數據庫從Oracle 8升級到Oracle 9,就必須更新存儲概要或者必須確認它們不再被使用.(事實上,別名為dbms_outln包outln_pkg包含一個特別的存儲過程 update_signatures來處理這個問題.
不過,關于Oracle 9中這些表的最意義重大的事情卻是對查詢語句中涉及到的文本與對象的極度詳細描述.創建圖-3中顯示的例子,并在繼續閱讀之前詳細查看ol$hints表中的內容.
drop table t1;
create table t1
nologging
as
select
rownum id,
rownum n1,
object_name,
rpad('x',500) padding
from
all_objects
where
rownum <= 100
;
alter table t1
add constraint t1_pk primary key (id);
create index t1_i1 on t1(n1);
analyze table t1 compute statistics;
create or replace outline demo_1 on
select * from t1
where id = 5
and n1 = 10
;
Figure 3 Sample code.
這個例子立足于一個簡單的小表,包含兩組相近的列,其中一個列為逐漸(從而也創建了索引),另外包含一個簡單的非唯一索引.我們為一個典型的查詢創建一個存儲概要來查看我們可以如何對待它.
如果針對由這個例子創建的存儲概要demo_1運行圖-1中的示例查詢,我們將發現這個查詢將附帶6個提示.
STAGE NODE HINT
3 1 NO_EXPAND
3 1 ORDERED
3 1 NO_FACT(T1)
3 1 INDEX(T1 T1_PK)
2 1 NOREWRITE
1 1 NOREWRITE
不出意外,其中的第四行顯示我們將使用主鍵索引來訪問這張表.如果我們實際上想要Oracle使用這個非唯一索引T1_I1訪問表,我們該對存儲概要做什么呢?理論上講,我們可以調整這個存儲概要以使得
3 1 INDEX(T1 T1_PK)
變成
3 1 INDEX(T1 T1_I1)
新特性
我們可以做的第一件事是查看包dbms_outln_edit.這個包在Oracle 9中引入,正如它的名字提示的那樣,它的目標是編輯存儲概要,這看上去令人充滿希望.
然而,查看包的方法列表,檢查文檔手冊,我們發現這個包只包含如下幾個”編輯相關”的方法.
CREATE_EDIT_TABLES
DROP_EDIT_TABLES
CHANGE_JOIN_POS
前兩個方法允許我們創建或刪除outln用戶擁有的表的本地拷貝.第三個方法允許我們交換一個存儲概要計劃中的表連接順序. 哪怕僅僅是幫助我們修改一個簡單的提示的方法也是沒有的.目前,這個包看上去實際上一無是處-但是它們注定會越來越完善.
當然B方案就是去侵入它了!如果我們登錄到outln用戶,并自己診察ol$hints表(也就是支撐視圖user_outline_hints的表)的內容,我們可以嘗試下面的這個更新操作:
update ol$hints
set
hint_text = 'INDEX(T1 T1_I1)'
where
ol_name = 'demo_1'
and hint# = 4
;
登錄回到我們的測試Schema,清空共享池,并且打開存儲概要:
connect test_user/test
alter system flush shared_pool;
alter session set use_stored_outlines = true;
實際上,我們將發現侵入的存儲概要確實如你所愿了.但是這是一個讓人不爽的解決方案,
因為我們一直會給一個關于”更改數據字典表”的嚴厲的警告.
舊方法(1)
接著,我們的目標就是尋找一種迂回但又看似無害的方法來改變存儲概要表的內容,并且不需要直接的侵入存儲概要表.
從前(在Oracle 9以前),我們有多種實現辦法,它們都是基于這樣一個事實,存儲概要的效果僅僅取決于進來的SQL語句的文本,而完全不關心對對象類型或者對象的所有者.
將表替換成添加過提示的視圖是一種有效的方法.(我相信,這種方法最初是由Tom Kyte在它的《Expert One on One: Oracle》這本書中介紹的).
連接到另外一個擁有表T1的訪問權限的Schema,按照下面的定義創建一個添加過提示的視圖,視圖與表的名稱保持一致.
Create or replace view t1 as
Select /*+ index(t1,t1_i1) */
*
from test_user.t1;
一旦視圖創建完成,就在這個schema下使用下面的這個命令”重編譯”這個已存在的存儲概要.
alter outline demo_1 rebuild;
注意:必須擁有權限alter any outline才可以執行這個命令.
如果登錄回到原來的schema,清空緩存(flush shared pool),并且啟用存儲概要,我們將會發現原來的查詢語句現在如愿以償的使用上了索引T1_I1.
3 1 INDEX(T1 T1_I1)
這樣為什么可行?因為存儲概要并不屬于任何一個schema. 當我們在另外一個schema中重編譯這個稱為demo_1的存儲概要的時候,名稱T1應用到了一個本地的包含提示的視圖上了,因此Oracle將這個提示包裝進了真實的執行計劃中,從而也進入了這個存儲概要.通過查看視圖user_outline_hints,將會發現關鍵的那一行已經變成了
原文轉自:http://blogread.cn/it/article/1030