正则表达式挂起在Oracle 11g中

时间:2013-06-26 15:27:51

标签: regex oracle

我正在使用Oracle 11g。以下语句大约需要3秒钟执行:

select  case when regexp_like(
    'blahblahblahblah.blah@blah-blah.blah.gov.uk', 
    '^[\-a-zA-Z0-9_''^&\+\?\:]+(\.?[\-a-zA-Z0-9_''^&\+\?\:]+)*@([a-zA-Z0-9]+\.)+[a-zA-Z]{2,3}$') 
    then 'true' else 'false' end

在电子邮件地址中添加另一个字符:

'blahblahblahblah.blahx@blah-blah.blah.gov.uk'

需要6秒。另一个角色12,然后是24,48,依此类推。所以:

'blahblahblahblah.blahxxxxx@blah-blah.blah.gov.uk'

需要大约96秒才能运行。

但是,请删除连字符:

'blahblahblahblah.blahxxxxx@blahblah.blah.gov.uk'

它会立即运行。

有人知道这里发生了什么吗?

1 个答案:

答案 0 :(得分:6)

您的正则表达式导致catastrophic backtracking

简而言之,您的正则表达式的术语可以两者捕获输入的相同部分,但未能这样做。正则表达式引擎必须在失败之前尝试所有组合,并且由于创建了匹配树,每个额外字符使得匹配的方式数量加倍。创建和遍历此树会导致几何指数执行时间与2 ^ n成比例 - 您将看到它。

您可能会发现将双重表达式更改为占有量词(即++而不是+)会停止此行为,因为一旦消耗了字符++,它们就会 消耗。


顺便说一句,这个表达

[\-a-zA-z0-9_''^&\+\?\:]

可以改写为:

[-\w''^&+?:]

由于:

  • 在一个角色类里面(差不多)所有角色都失去了特殊的正则表达式意思
  • 第一个或最后一个破折号是一个文字破折号(不是范围)
  • \w == [a-zA-Z0-9_]