2016-04-27 61 views
0

我通常會在StackOverflow處於絕望狀態時觸及......所以......任何想法或見解關於優化將是非常讚賞...使用「..或列類似'字符串%'或...」來優化查詢「

問題:我有一些疑問,其中,在where子句中,我有這樣的事情:

WHERE VERSION = 462 
     AND (CSB_CART_MAN LIKE '12010%' 
     OR CSB_CART_MAN LIKE '12011%' 
     OR CSB_CART_MAN LIKE '12013%' 
    . 
    . 
    .) 
and around a thousound conditions like the ones above. 
  • CSB_CART_MAN是VARCHAR2。
  • 數據大小 - 160行,51列。

正如預期的那樣,這是超級慢...

如何優化這樣的情況的任何想法? (千 「或類似 'XXX%'」)

數據例如:

CSB_CART_MAN - 270090 
CSB_CART_MAN - 2700910 
CSB_CART_MAN - 13911 
CSB_CART_MAN - 13912 
CSB_CART_MAN - 139130 

這些是什麼號碼? - 這些數字代表國際會計準則,也稱爲「國際會計估計」

+0

CSB_CART_MAN列中的數據示例 –

+0

都是模式正好有五個字符後跟一個&符號? –

+0

你提到的所有這些查詢是否包含相同的固定模式列表? –

回答

1

也許它適用於使用regexp_like而不是標準樣? 你的樣品上方可以寫成:

... WHERE regexp_like(CSB_CART_MAN, '^1201[0,1,3]') 

BTW。:我最喜歡的地方,形成一個正則表達式模式和測試它是https://regex101.com/

...和你的新提供的數據樣本:

WITH d AS (
    SELECT 270090 CSB_CART_MAN FROM dual UNION ALL 
    SELECT 2700910 CSB_CART_MAN FROM dual UNION ALL 
    SELECT 13911 CSB_CART_MAN FROM dual UNION ALL 
    SELECT 13912 CSB_CART_MAN FROM dual UNION ALL 
    SELECT 139130 CSB_CART_MAN FROM dual 
    ) 
SELECT * 
    FROM d 
WHERE regexp_like(d.csb_cart_man, '^(2700|1391)\d{1,3}$') 

這意味着,值必須開始(^)或者用 「2700」 或 「1391」,隨後用1到3位,然後到達結束($)

0

我想看看把搜索字符串爲表(可能是臨時表)和JOIN荷蘭國際集團向相反:

SELECT 
    ... 
FROM 
    My_Table MT 
INNER JOIN Search_Criteria SC ON MT.CSB_CART_MAN LIKE SC.string_pattern 
WHERE 
    version = 462 
+0

我們將嘗試類似於您的方法。在這種情況下,我認爲臨時表可能是一個好主意。 –

0

你想表現聰明的查詢,則必須進行濾波前4位的數據,加入這個表主表和篩選再次任何你想要

這樣

SELECT 
    MT.* 
FROM 
    My_Table MT 
INNER JOIN(
     select * from my_table 
     where version = 462 
     cSB_CART_MAN LIKE '1201%')a 
ON a.id=mt.id 
WHERE 
(a.CSB_CART_MAN LIKE '12010%' 
     OR a.CSB_CART_MAN LIKE '12011%' 
     OR a.CSB_CART_MAN LIKE '12013%' 
    . 
    . 
    .) 
+0

我想知道爲什麼加入? (cSB_CART_MAN LIKE'1201%')和 (a.CSB_CART_MAN LIKE'12010%' 或a.CSB_CART_MAN LIKE'12011%' 或a.CSB_CART_MAN LIKE'12013%'..)也得到一個好的計劃? – Serg

+0

@Serg join用於過濾該表上的數據,然後應用條件來獲取加入結果。 –

0

擁有約一千OR條件,就沒有多大意義了DBMS使用索引。該表必須按記錄讀取記錄並與列表進行比較。所以我必須快速地進行比較。

您正在使用LIKE這是一個模式匹配運算符。你給它一個模式,例如'12010%',必須解析wildchars('%'和'_')。有可能尋找像'1_2%345%'這樣複雜的東西,所以它必須有一個相當複雜的算法來做到這一點。正是因此,可能要好得多,恕不wildchars一個明確的對比:

substr(csb_cart_man, 1, 5) = '12010' 

我被教導,使用的功能,如substr在列使它不可能對優化器使用索引,而它可能會使用索引like 'xxx%'. That sounds kind of strange to me. If the optimizer is able to examine 'xxx%' on whether it starts with non-wildcard characters, why can't it see the 1 in substr(col,1,n)`?但無論如何,如前所述,無論如何在您的查詢中使用索引都沒有意義,所以沒問題。分別

select * 
from mytable 
where version = 462 
and substr(csb_cart_man, 1, 5) in ('12010', '12011', '12013', ...); 

從而爲多種長度:

我會這樣編寫查詢

select * 
from mytable 
where version = 462 
and 
(
    substr(csb_cart_man, 1, 5) in ('12010', '12011', '12013', ...) 
    or 
    substr(csb_cart_man, 1, 6) in ('120444', '120555', '120777', ...) 
); 

有了一個固定的長度,你可以嘗試用一個函數索引,但如前所述,我不t認爲它會被使用:

create index idx_fivechars on mytable(version , substr(csb_cart_man, 1, 5)); 
+0

謝謝我的朋友。我認爲substr方法可能是一個非常好的解決方案。我們將嘗試這個解決方案。我會盡快回復你。上校:我無法贊成你。沒有足夠的聲望點。 –

+0

不要擔心點。希望我的查詢有幫助。不過,您應該始終回答評論部分中的問題,以便我們提供幫助。 –

+0

明白了!謝謝。 –