当我处于绝望的深层状态时,我通常会联系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.
正如所料,这是超级慢......
有关如何优化此类情况的任何想法? (一千个"或类似' XXX%'")
数据示例:
CSB_CART_MAN - 270090 CSB_CART_MAN - 2700910 CSB_CART_MAN - 13911 CSB_CART_MAN - 13912 CSB_CART_MAN - 139130
这些数字是多少? - 这些数字代表IAS,也称为"国际会计估计"
答案 0 :(得分:1)
也许它适用于使用regexp_like而不是标准的? 您上面的示例可以写成:
... WHERE regexp_like(CSB_CART_MAN, '^1201[0,1,3]')
顺便说一下:我最喜欢的地方形成一个正则表达式并测试它是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位数,然后到达结尾($)
答案 1 :(得分:0)
我会考虑将搜索字符串放入表格(可能是临时表格)并JOIN
将其放入:
SELECT
...
FROM
My_Table MT
INNER JOIN Search_Criteria SC ON MT.CSB_CART_MAN LIKE SC.string_pattern
WHERE
version = 462
答案 2 :(得分: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%'
.
.
. )
答案 3 :(得分:0)
有大约一千OR
个条件,DBMS使用索引没有多大意义。必须逐个记录该表并与列表进行比较。所以我必须快速完成比较。
您使用的是LIKE
模式匹配运算符。你给它一个模式,例如必须为wildchars('%'和'_')解析'12010%'。有可能找到像'1_2%345%'那样复杂的东西,所以它必须有一个相当复杂的算法来做到这一点。因此,在没有野人的情况下进行明确的比较可能要好得多:
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', ...)
);
使用一个固定长度你可以尝试使用函数索引,但如上所述,我不认为它会被使用:
create index idx_fivechars on mytable( version , substr(csb_cart_man, 1, 5) );