2013-05-27 46 views
6

我有一個爲大量區域定義的電話號碼前綴列表(在gvcode和cgi中定義的查詢中)。 我需要有效地找到匹配給定號碼PHONE_NR的最長前綴。在ORACLE中搜索最長前綴的最快方法

我對字段數字(包含表單+ 48%,+ 49%,+ 1%,+ 1232%等等)中的前綴使用反向的LIKE子句。

因此我無法在該字段上使用正常的索引。

我設法通過在gvcode和cgi字段(它們是主鍵的一部分(前兩列))上使用IOT以獲得實質性改進。 我也查看了一些oracle文本索引,但是找不到一個與表中較短前綴匹配的較長輸入。

是否有任何其他方式執行這種搜索比這種方法更快。

下面是查詢,它給出了所有匹配的前綴列表(我之後對數字長度進行排序)。

select t.gvcode, t.digits 
       from NUMBERS t 
        where 
         t.gvcode=ZONE_SET_CODE 
         and t.cgi=cgi_f 
         and (PHONE_NR like t.digits) 
         order by length(digits) desc 
+0

也許如果你在'substr(digits,2,length(digits)-1)'上創建一個基於函數的索引,然後在查詢where子句中添加另一個條件'substr(digits,2,length(digits)-1 )<= PHONE_NR'你可以在某些情況下看到一些改進 –

+0

應該是'和substr(數字,1,長度(數字)-1)<= PHONE_NR'(不需要刪除'+') –

回答

1

除了「位數」索引之外,您還可以在rpad(substr(digits,1,length(digits)-1), 10, '9')上創建索引。 「10」是您想要支持的最大長度。您將添加一個附加條件where子句:rpad(substr(digits,1,length(digits)-1), 10, '9') >= PHONE_NR

你的SQL是:

select t.gvcode, t.digits 
from NUMBERS t 
    where 
     t.gvcode=ZONE_SET_CODE 
     and t.cgi=cgi_f 
     and PHONE_NR like t.digits 
     and substr(digits, 1, length(digits)-1) <= PHONE_NR 
     and rpad(substr(digits,1,length(digits)-1), 10, '9') >= PHONE_NR 
order by length(digits) desc 

這裏是sqlfiddle

0

我不確定這會真的有幫助,但我認爲這值得一試。

創建於substr(digits, 1, length(digits)-1)一個函數的索引(這僅僅是指數的數字沒有 '%')

然後在你的查詢,你可以添加另一個條件:

AND substr(digits, 1, length(digits)-1) <= PHONE_NR 

Here is a sqlfiddle demo

這個想法是,與詞法比較,你可以「切出」後面的所有數字是PHONE_NR

1

我可能聽起來很蠢,但是當我遇到了這樣的問題,我在大多數非節省空間的蠻力方式去:

比方說:

L=length of longest prefix to match (without obvious +, of course) 

添加L其他字段命名它們,例如,P1, P2,...,PL

更新與

UPDATE NUMBERS set P1=SUBSTR(PHONE_NR,1,1), P2=SUBSTR(PHONE_NR,1,2), ..., PL=SUBSTR(PHONE_NR,1,L) 

這些字段(在未來,你可以在做到這一點trigger)

現在你有L個字段來創建索引並與你喜歡的任何東西進行比較。

0

好的一個例子,只是寫,因爲我有同樣的問題。 如果您知道前綴長度的範圍,則可以執行與以下類似的操作。以下示例假定前綴長度爲2-6

select t.num, coalesce(p6.PREFIX, p5.PREFIX, p4.PREFIX, p3.PREFIX, p2.PREFIX) PREFIX 
    from NUMBERS t 
LEFT OUTER JOIN PREFIXES p2 ON substr(t.num,1,2)=p2.PREFIX 
LEFT OUTER JOIN PREFIXES p3 ON substr(t.num,1,3)=p3.PREFIX 
LEFT OUTER JOIN PREFIXES p4 ON substr(t.num,1,4)=p4.PREFIX 
LEFT OUTER JOIN PREFIXES p5 ON substr(t.num,1,5)=p5.PREFIX 
LEFT OUTER JOIN PREFIXES p6 ON substr(t.num,1,6)=p6.PREFIX 

平等聯接儘可能好,您可以得到。

我相信它的運行方式比這裏的任何其他可能的解決方案更好,希望它可以幫助人誰對同一問題

Sqlfiddle link從sailaway的答案,其劇本修改失蹄還是給出了所有的比賽,而不是隻有最長的一個