在编写EJB-QL的解析器的时候偶然发现的。
假设要解析的EJB-QL的值为:
SELECT OBJECT(al) FROM AppLibraryConfig al WHERE al.id=?1 AND al.status=true

下面看看不同的表达式Pattern所需要的执行时间,解析的伪代码为:
long start=System.currentTimeMillis();
Pattern pattern = Pattern.compile(getPatternText(), Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(query);
if (matcher.matches()) {
        int groupCount = matcher.groupCount();
        for (int i = 0; i <= groupCount; i++)
        {
            System.out.println("Group " + i + " :[" + matcher.group(i) + "]");
        }
}
System.out.println(System.currentTimeMillis()-start);

现在看看不同的getPatternText()的值得到的不同结果。

1、性能最好的:
SELECT\\s+(DISTINCT)?\\s*OBJECT\\s*\\(\\s*(\\w+)\\s*\\)\\s+FROM\\s+\\w+(?:\\s+AS)?\\s+\\2\\s*
WHERE\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*
(?:AND\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*)*
这个的执行时间为0
2、修改一下,把最后的那个*修改为?:
SELECT\\s+(DISTINCT)?\\s*OBJECT\\s*\\(\\s*(\\w+)\\s*\\)\\s+FROM\\s+\\w+(?:\\s+AS)?\\s+\\2\\s*
WHERE\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*
(?:AND\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*)?
这个的执行时间为15毫秒
3、加长,把后面的AND部分复制一遍:
SELECT\\s+(DISTINCT)?\\s*OBJECT\\s*\\(\\s*(\\w+)\\s*\\)\\s+FROM\\s+\\w+(?:\\s+AS)?\\s+\\2\\s*
WHERE\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*
(?:AND\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*)?
(?:AND\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*)?
这个的执行时间为31毫秒
4、继续加长,把后面的AND部分复制一遍:
SELECT\\s+(DISTINCT)?\\s*OBJECT\\s*\\(\\s*(\\w+)\\s*\\)\\s+FROM\\s+\\w+(?:\\s+AS)?\\s+\\2\\s*
WHERE\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*
(?:AND\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*)?
(?:AND\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*)?
(?:AND\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*)?
这个的执行时间为656毫秒
5、继续加长,把后面的AND部分复制一遍:
SELECT\\s+(DISTINCT)?\\s*OBJECT\\s*\\(\\s*(\\w+)\\s*\\)\\s+FROM\\s+\\w+(?:\\s+AS)?\\s+\\2\\s*
WHERE\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*
(?:AND\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*)?
(?:AND\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*)?
(?:AND\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*)?
(?:AND\\s+(\\2\\.\\w+)\\s*(=|is|<>|>=|>|<|<=)\\s*((?:\\??\\d+)|(?:null)|(?:true)|(?:false))\\s*)?
这个的执行时间为18547毫秒

看到问题了吧。表达式长了以后,这个性能的损害非常非常的大。
其实第一个表达式的匹配范围比最后一个更好,但是问题是,通过matcher.group()得到的是最后一次匹配的,现在还不知道如何解决,但是肯定可以解决。找到方法后再更新这个。

(Visited 253 times, 2 visits today)