在 Oracle 中使用 null(带正则表达式)-非常慢

using null in Oracle (with regexp)-very slow

提问人:Lawrence Block 提问时间:11/3/2023 更新时间:11/4/2023 访问量:29

问:

试图弄清楚我可以做些什么来加快查询速度,就像当我尝试基于不为空返回值时一样 - 返回观察结果需要很长时间,我需要终止工作。正则表达式语句本身似乎没问题。

由于 IP 问题,我屏蔽了一些表名并更改了 var 名称。此外,我没有测试集,因为它在虚拟集中工作正常,但在实际生产环境中工作正常 - 这是它停滞不前的地方,所以我正在寻找解决此问题的一般概念。

任何意见/建议表示赞赏。谢谢。

select prev_pod.mrn_id, prev_pod.pat_enc_id, prev_pod.contact_date, note_text,
coalesce(REGEXP_substr(NOTE_TEXT, '(new)+{1,10}([^.|,|?|$])(wound)+{1,10}([^.|,|?|$])(evaluation)',1,1,'i'), 
REGEXP_substr(NOTE_TEXT, '(foot)+{1,10}([^.|,|?|$])(wound)+{1,10}([^.|,|?|$])(clinic)+{1,10}([^.|,|?|$])(new)',1,1,'i')) as STR

    
from HNO_xxx inner join PREV_POD on HNO_xxx.pat_enc_id=prev_pod.pat_enc_id
                                inner join  HNO_NOTE_TEXT  ON     HNO_xxx.note_id = HNO_NOTE_xxx.note_id and HNO_NOTE_xxx.LINE=1)

select * from ntes where STR IS NOT NULL); --THIS IS THE PROBLEM
甲骨文 null

评论

2赞 p3consulting 11/4/2023
正则表达式本质上是缓慢的,因此您应该首先通过选择可能与子查询中的正则表达式匹配的行来减少要处理的行数:包含 (new and wound and evaluation) 或 (foot and wound and clinic and new) 的行数。
0赞 Lawrence Block 11/4/2023
我有它,所以由于这个原因,它总共不到 100 行 - 当它不为 null 时不选择 - 它会在 2 分钟内返回结果。如果我尝试选择何时不为空,我必须在 10-15 分钟后终止查询。

答:

0赞 Paul W 11/4/2023 #1

如前所述,Oracle 必须 100% 读取 并通过复杂的 REGEXP 逻辑运行其所有行,以满足您的谓词。为了加快速度,我建议首先使用并行性:HNO_NOTE_TEXTWHERE str IS NOT NULL

   select /*+ parallel(8) */ * from ntes where str is not null

第二件事是检查执行计划,看看计划是否改变了连接顺序。如果应用谓词 to(来自 ),它可能会以 和 join to 开头,然后按该顺序开头,而如果没有谓词,它可能会使用不同的连接顺序。如果这些联接列在一个方向上存在索引,但在另一个方向上没有索引,则可以解释运行时的差异。STRHNO_NOTE_TEXTHNO_NOTE_TEXTHNO_xxxPREV_POD

没有明显限制的谓词,因此您不希望在此处使用索引。检查计划,如果看到正在使用的索引,则可能需要使用提示来强制它执行全表扫描 + 哈希联接。它可能仅仅因为上面建议的并行提示而决定这样做,但如果没有,请编辑您的视图:/*+ USE_HASH(table_alias) */

select /*+ USE_HASH(hno_xxx prev_pod hno_note_text) PARALLEL(8) */ prev_pod.mrn_id, prev_pod.pat_enc_id, prev_pod.contact_date, note_text,
coalesce(REGEXP_substr(NOTE_TEXT, '(new)+{1,10}([^.|,|?|$])(wound)+{1,10}([^.|,|?|$])(evaluation)',1,1,'i'), 
REGEXP_substr(NOTE_TEXT, '(foot)+{1,10}([^.|,|?|$])(wound)+{1,10}([^.|,|?|$])(clinic)+{1,10}([^.|,|?|$])(new)',1,1,'i')) as STR

    
from HNO_xxx inner join PREV_POD on HNO_xxx.pat_enc_id=prev_pod.pat_enc_id
                                inner join  HNO_NOTE_TEXT  ON     HNO_xxx.note_id = HNO_NOTE_xxx.note_id and HNO_NOTE_xxx.LINE=1)

然后查询它:

select * from ntes where STR IS NOT NULL

请注意,如果其他人使用该视图并对其应用狭义谓词,这些提示将伤害他们。如果是这种情况,你最好不要使用视图,直接针对表编写 SQL,这样你的提示是私有的。