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);
+    }
+    
 }


Reply via email to