提交 0e4cbb32 authored 作者: Noel Grandin's avatar Noel Grandin

improve performance of queries that use LIKE 'foo%' - 10x in the case of one of my queries

上级 f31539cc
...@@ -21,6 +21,8 @@ Change Log ...@@ -21,6 +21,8 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>improve performance of queries that use LIKE 'foo%' - 10x in the case of one of my queries
</li>
<li>Issue #229: DATEDIFF does not work for 'WEEK' <li>Issue #229: DATEDIFF does not work for 'WEEK'
</li> </li>
<li>Issue #156: Add support for getGeneratedKeys() when executing commands via PreparedStatement#executeBatch <li>Issue #156: Add support for getGeneratedKeys() when executing commands via PreparedStatement#executeBatch
......
...@@ -7,7 +7,6 @@ package org.h2.expression; ...@@ -7,7 +7,6 @@ package org.h2.expression;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException; import java.util.regex.PatternSyntaxException;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -38,6 +37,7 @@ public class CompareLike extends Condition { ...@@ -38,6 +37,7 @@ public class CompareLike extends Condition {
private char[] patternChars; private char[] patternChars;
private String patternString; private String patternString;
/** one of MATCH / ONE / ANY */
private int[] patternTypes; private int[] patternTypes;
private int patternLength; private int patternLength;
...@@ -47,6 +47,8 @@ public class CompareLike extends Condition { ...@@ -47,6 +47,8 @@ public class CompareLike extends Condition {
private boolean ignoreCase; private boolean ignoreCase;
private boolean fastCompare; private boolean fastCompare;
private boolean invalidPattern; private boolean invalidPattern;
/** indicates that we can shortcut the comparison and use startsWith */
private boolean shortcutToStartsWith;
public CompareLike(Database db, Expression left, Expression right, public CompareLike(Database db, Expression left, Expression right,
Expression escape, boolean regexp) { Expression escape, boolean regexp) {
...@@ -196,6 +198,8 @@ public class CompareLike extends Condition { ...@@ -196,6 +198,8 @@ public class CompareLike extends Condition {
// column is not a varchar - can't use the index // column is not a varchar - can't use the index
return; return;
} }
// Get the MATCH prefix and see if we can create an index condition from
// that.
int maxMatch = 0; int maxMatch = 0;
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
while (maxMatch < patternLength && patternTypes[maxMatch] == MATCH) { while (maxMatch < patternLength && patternTypes[maxMatch] == MATCH) {
...@@ -253,20 +257,15 @@ public class CompareLike extends Condition { ...@@ -253,20 +257,15 @@ public class CompareLike extends Condition {
String value = l.getString(); String value = l.getString();
boolean result; boolean result;
if (regexp) { if (regexp) {
// result = patternRegexp.matcher(value).matches();
result = patternRegexp.matcher(value).find(); result = patternRegexp.matcher(value).find();
} else if (shortcutToStartsWith) {
result = value.regionMatches(ignoreCase, 0, patternString, 0, patternLength-1);
} else { } else {
result = compareAt(value, 0, 0, value.length(), patternChars, patternTypes); result = compareAt(value, 0, 0, value.length(), patternChars, patternTypes);
} }
return ValueBoolean.get(result); return ValueBoolean.get(result);
} }
private boolean compare(char[] pattern, String s, int pi, int si) {
return pattern[pi] == s.charAt(si) ||
(!fastCompare && compareMode.equalsChars(patternString, pi, s,
si, ignoreCase));
}
private boolean compareAt(String s, int pi, int si, int sLen, private boolean compareAt(String s, int pi, int si, int sLen,
char[] pattern, int[] types) { char[] pattern, int[] types) {
for (; pi < patternLength; pi++) { for (; pi < patternLength; pi++) {
...@@ -300,6 +299,12 @@ public class CompareLike extends Condition { ...@@ -300,6 +299,12 @@ public class CompareLike extends Condition {
return si == sLen; return si == sLen;
} }
private boolean compare(char[] pattern, String s, int pi, int si) {
return pattern[pi] == s.charAt(si) ||
(!fastCompare && compareMode.equalsChars(patternString, pi, s,
si, ignoreCase));
}
/** /**
* Test if the value matches the pattern. * Test if the value matches the pattern.
* *
...@@ -376,6 +381,17 @@ public class CompareLike extends Condition { ...@@ -376,6 +381,17 @@ public class CompareLike extends Condition {
} }
} }
patternString = new String(patternChars, 0, patternLength); patternString = new String(patternChars, 0, patternLength);
/* optimises the common case of LIKE 'foo%' */
if (compareMode.getName().equals(CompareMode.OFF) && patternLength > 1) {
int maxMatch = 0;
while (maxMatch < patternLength && patternTypes[maxMatch] == MATCH) {
maxMatch++;
}
if (maxMatch == patternLength - 1 && patternTypes[patternLength-1] == ANY) {
shortcutToStartsWith = true;
}
}
} }
private boolean isFullMatch() { private boolean isFullMatch() {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论