警惕!自定義函式索引的那些陷阱及避坑術

2021-09-23 17:41:37 字數 2706 閱讀 4827

作者介紹

丁俊,dbaplus社群聯合發起人,新炬網路專家團成員,效能優化專家,oracle acea,itpub開發版資深版主。十年電信行業從業經驗,從事過系統開發與維護、業務架構和資料分析、系統優化等工作。

電子工業出版社終身榮譽作者,《劍破冰山-oracle開發藝術》副主編。

當我們對列使用了函式運算之後,如果此列沒有函式索引,那麼普通索引是無效的。比如where substr(name,1,3)='abc';如果建立了create index idx_t on t(name);

那麼謂詞是無法使用此索引做範圍掃瞄的。在oracle中允許定義函式索引(function based index,簡稱fbi),函式索引可以是基於內建函式的,也可以是自定義函式的,

本文主要講述基於自定義函式的索引用法及其注意點。

當需要對列進行複雜的運算,複雜的規則需要自定義函式的時候,如果需要走索引,那麼必須建立自定義函式的索引。建立自定義函式索引有幾點要注意:

1、自定義函式必須加deterministic關鍵字,讓oracle知道此函式對於每個入參的返回結果都是確定的唯一的。

道理很明顯,如果一樣的入參,結果不同,那麼查詢的結果必然有問題,必須要用這個關鍵字告訴oracle,此函式索引是可以信任的。但是有個問題得注意:因為自定義函式是一系列邏輯規則,就算定義的函式對每個入參返回的值不唯一(比如用了sysdate,random等運算),但是使用了deterministic關鍵字,讓oracle相信唯一,但是實際情況不唯一,那麼使用函式索引查詢的結果必然也是有問題的。所以使用函式索引要注意:必須從邏輯上確定對於一樣的入參返回的結果是一樣的,因為oracle不會檢查你的邏輯。

2、一旦改變函式定義,必須rebuild對應的函式索引

很顯然,函式索引中儲存的是表中的列或表示式作為自定義函式的引數的運算結果,如果函式改變,oracle不會自動rebulid

函式索引對應的值,這樣如果繼續使用函式索引,必然結果可能出錯。

下面分別對上面的內容舉例說明:

針對第1點的例子:

of course,現在的結果是沒有問題的,但是本身這個自定義函式中的to_date(param,'yyyy')針對不同月份的插入結果返回的都是當月的第一天,如果我是6月插入:

現在是查詢:

上面的結果是令人迷惑的,因為表裡儲存的有2行2013,但是最終結果卻只查詢出一行。

究其原因,就是自定義函式雖然使用了deterministic關鍵字,但是oracle只管有沒有這關鍵字,而不會管你的函式邏輯是否真的對每個相同的輸入,有一樣的輸出,這裡我們使用deterministic關鍵字,欺騙了oracle。很顯然,雖然在表裡儲存的2行都是2013,但是乙個5月份插入的,乙個6月份插入的,通過函式運算,乙個索引中儲存的是2013-5-1,乙個是2013-6-1,所以使用2013-5-1裡查詢的時候,只返回1行。如果自定義中有類似於dbms_random,sys_guid等不確定或隨時間變化值不同的,那麼也會產生此混亂結果。

另外很多書上說函式索引必須:

oracle使用函式索引,會進行查詢重寫,要求下面兩個引數開啟:       

query_rewrite_enabled=true

query_rewrite_integrity=trusted

經過測試,發現在本環境11g下無影響。

針對第2點的例子:

函式索引的函式定義不能隨便改變,改變就必須rebuild函式索引(or刪除重建),因為函式索引中會儲存對應函式運算的結果,然後在使用函式索引訪問的時候,不用再呼叫函式,so,函式改變,oracle不會級聯rebuild其函式索引,所以,改變函式邏輯不手動rebuild,必然是危險的。

走全表掃瞄,函式會對每行都呼叫1次。

無函式索引,全表掃瞄,訪問對每行都呼叫函式,一條sql訪問函式999次。如果使用函式索引,那麼必然在建立(dml)的時候,會自動呼叫函式,索引中儲存對應的key與函式運算結果值,所以,再使用到函式索引的時候,不用再呼叫函式,而且索引訪問還提高效率,達到多種提高效率的效果。

使用自定義函式索引是危險的,如果修改函式定義,沒有rebuild或刪除重建函式索引,那麼函式索引中儲存的還是舊的函式運算結果,這樣會導致錯誤:

總結:在不得不使用函式索引來提高效率的時候,別忘記了,隨時準備維護函式索引,而且別弄出奇奇怪怪的函式索引,導致亂七八糟的問題,那樣就不好了!

自定義函式及函式呼叫

在論壇中,發現有的道友對自定義函式的呼叫存在這以下問題 1 自定義函式宣告 函式呼叫 函式實現概念混淆 2 形參和實參混淆 3 自定義函式引數的傳值方式混淆 傳來傳去都不知道傳的到底是什麼?接下來,我就重點圍繞道友們常見的問題,說一說 1 自定義函式宣告 函式呼叫 函式實現 比如 交換兩個數的值的自...

自定義函式及函式的封裝

l 建立自定義函式的三種方式 js引擎預設以命名函式的形式來解讀函式,所以不能直接宣告匿名函式,解決方法 可以用變數 陣列或物件等資料將匿名函式儲存起來,例如button點選事件,以 及 var fn function a,b fn 100,200 對應呼叫 匿名函式的自呼叫 自執行匿名函式 新增括...

Javascript中的函式及自定義屬性

1.函式 將一系列 或者操作行為打包到一起形成的內容就是函式,是一塊有特定功能的 2.函式的分類 a.具名函式 有函式名的就是具名函式 function foo foo 執行函式,表示函式執行成功了注 函式執行時需要加 也就是說,直接加括號表示函式執行了。on事件後面所賦值的內容一定是函式,而不是函...