我正在使用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'
它会立即运行。
有人知道这里发生了什么吗?
答案 0 :(得分:6)
您的正则表达式导致catastrophic backtracking。
简而言之,您的正则表达式的术语可以两者捕获输入的相同部分,但未能这样做。正则表达式引擎必须在失败之前尝试所有组合,并且由于创建了匹配树,每个额外字符使得匹配的方式数量加倍。创建和遍历此树会导致几何指数执行时间与2 ^ n成比例 - 您将看到它。
您可能会发现将双重表达式更改为占有量词(即++
而不是+
)会停止此行为,因为一旦消耗了字符++
,它们就会 消耗。
顺便说一句,这个表达
[\-a-zA-z0-9_''^&\+\?\:]
可以改写为:
[-\w''^&+?:]
由于:
\w
== [a-zA-Z0-9_]