2016-04-27 60 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

明白了!谢谢。 –