Author: thomasm
Date: Tue May 19 13:56:55 2015
New Revision: 1680294
URL: http://svn.apache.org/r1680294
Log:
OAK-2873 Performance problems with many "or" conditions
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/LargeQueryTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java?rev=1680294&r1=1680293&r2=1680294&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java
Tue May 19 13:56:55 2015
@@ -318,12 +318,30 @@ abstract class Expression {
}
String commonLeft = getCommonLeftPart();
if (commonLeft == null) {
+ // the case:
+ // (other>0 or x=1) or x=2
+ // can be converted to:
+ // other>0 or (x=1 or x=2)
+ // which can then be optimized
+ if (left instanceof OrCondition) {
+ OrCondition orLeft = (OrCondition) left;
+ Expression l1 = orLeft.left;
+ Expression l2 = orLeft.right;
+ OrCondition orRight = new OrCondition(l2, right);
+ Expression o2 = orRight.optimize();
+ if (o2 != orRight) {
+ return new OrCondition(l1, o2);
+ }
+ }
return this;
}
// "@x = 1 or @x = 2" is converted to "@x in (1, 2)"
if (left instanceof InCondition) {
InCondition in = (InCondition) left;
in.list.addAll(right.getRight());
+ // return a new instance, because we changed
+ // the list
+ in = new InCondition(in.getLeft(), in.list);
return in;
}
ArrayList<Expression> list = new ArrayList<Expression>();
@@ -707,6 +725,8 @@ abstract class Expression {
final Selector selector;
final String name;
+ private String cacheString;
+ private boolean cacheOnlySelector;
/**
* If there was no "@" character in front of the property name. If that
@@ -723,6 +743,11 @@ abstract class Expression {
@Override
public String toString() {
+ if (cacheString != null) {
+ if (cacheOnlySelector == selector.onlySelector) {
+ return cacheString;
+ }
+ }
StringBuilder buff = new StringBuilder();
if (!selector.onlySelector) {
buff.append(selector.name).append('.');
@@ -732,7 +757,9 @@ abstract class Expression {
} else {
buff.append('[').append(name).append(']');
}
- return buff.toString();
+ cacheString = buff.toString();
+ cacheOnlySelector = selector.onlySelector;
+ return cacheString;
}
@Override
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java?rev=1680294&r1=1680293&r2=1680294&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
Tue May 19 13:56:55 2015
@@ -436,7 +436,7 @@ public class XPathToSQL2Converter {
while (readIf("and")) {
a = new Expression.AndCondition(a, parseCondition());
}
- return a;
+ return a.optimize();
}
private Expression parseCondition() throws ParseException {
@@ -465,7 +465,7 @@ public class XPathToSQL2Converter {
}
a = parseCondition(e);
}
- return a;
+ return a.optimize();
}
private Expression.Condition parseCondition(Expression left) throws
ParseException {
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/LargeQueryTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/LargeQueryTest.java?rev=1680294&r1=1680293&r2=1680294&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/LargeQueryTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/LargeQueryTest.java
Tue May 19 13:56:55 2015
@@ -21,12 +21,13 @@ import static org.junit.Assert.assertEqu
import java.text.ParseException;
import org.apache.jackrabbit.oak.query.xpath.XPathToSQL2Converter;
+import org.h2.util.Profiler;
import org.junit.Test;
public class LargeQueryTest {
@Test
- public void test() throws ParseException {
+ public void testSimpleOr() throws ParseException {
StringBuilder buff = new StringBuilder("//*[");
StringBuilder buff2 = new StringBuilder(
"select [jcr:path], [jcr:score], * from [nt:base] as a where
[x] in(");
@@ -46,4 +47,46 @@ public class LargeQueryTest {
buff2.append(" /* xpath: ").append(xpath).append(" */");
assertEquals(buff2.toString(), sql2);
}
+
+ @Test
+ public void testCombinedOr() throws ParseException {
+ StringBuilder buff = new StringBuilder("//*[");
+ StringBuilder buff2 = new StringBuilder(
+ "select [jcr:path], [jcr:score], * from [nt:base] as a where
[x] in(");
+ int step = 111;
+ for (int i = 0; i < 5000; i++) {
+ if (i % step == 2) {
+ if (i > 0) {
+ buff.append(" or ");
+ }
+ buff.append("@x>").append(i);
+ buff2.append(") union select [jcr:path], [jcr:score], * from
[nt:base] as a " +
+ "where [x] > ").append(i);
+ buff2.append(" union select [jcr:path], [jcr:score], * from
[nt:base] as a " +
+ "where [x] in(");
+ } else {
+ if (i > 0) {
+ buff.append(" or ");
+ }
+ buff.append("@x=").append(i);
+ if (i > 0 && i % step != 3) {
+ buff2.append(", ");
+ }
+ buff2.append(i);
+ }
+ }
+ buff.append("]");
+ buff2.append(")");
+ String xpath = buff.toString();
+ XPathToSQL2Converter conv = new XPathToSQL2Converter();
+ long start = System.currentTimeMillis();
+ Profiler prof = new Profiler().startCollecting();
+ String sql2 = conv.convert(xpath);
+ long time = System.currentTimeMillis() - start;
+ System.out.println("time: " + time);
+ System.out.println(prof.getTop(5));
+ buff2.append(" /* xpath: ").append(xpath).append(" */");
+ assertEquals(buff2.toString(), sql2);
+ }
+
}