This is an automated email from the ASF dual-hosted git repository.

mblow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 29f1d423b7 [ASTERIXDB-3377][COMP]: CBO choosing wrong index
29f1d423b7 is described below

commit 29f1d423b7a8ebff0abc7ff40534463a66b1a33b
Author: Vijay Sarathy <[email protected]>
AuthorDate: Mon Apr 15 15:07:08 2024 -0700

    [ASTERIXDB-3377][COMP]: CBO choosing wrong index
    
    Change-Id: I81a6dcca634d3d30f0b101baabe4093fb01123d0
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/18236
    Integration-Tests: Jenkins <[email protected]>
    Tested-by: Jenkins <[email protected]>
    Reviewed-by: <[email protected]>
    Reviewed-by: Vijay Sarathy <[email protected]>
---
 .../asterix/optimizer/rules/cbo/JoinEnum.java      | 24 ++++++++++
 .../asterix/optimizer/rules/cbo/JoinNode.java      | 19 ++++++--
 .../apache/asterix/optimizer/rules/cbo/Stats.java  | 54 +++++++++++++---------
 .../hints-use-index/hints-use-index-16.plan        |  4 +-
 4 files changed, 73 insertions(+), 28 deletions(-)

diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
index e419eea068..951648aa3b 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
@@ -30,6 +30,7 @@ import java.util.Set;
 
 import org.apache.asterix.common.annotations.IndexedNLJoinExpressionAnnotation;
 import 
org.apache.asterix.common.annotations.SecondaryIndexSearchPreferenceAnnotation;
+import 
org.apache.asterix.common.annotations.SkipSecondaryIndexSearchExpressionAnnotation;
 import org.apache.asterix.common.exceptions.AsterixException;
 import org.apache.asterix.common.exceptions.ErrorCode;
 import org.apache.asterix.metadata.declared.DataSource;
@@ -384,6 +385,29 @@ public class JoinEnum {
         return false;
     }
 
+    public SkipSecondaryIndexSearchExpressionAnnotation 
findSkipIndexHint(AbstractFunctionCallExpression condition) {
+        if 
(condition.getFunctionIdentifier().equals(AlgebricksBuiltinFunctions.AND)) {
+            for (int i = 0; i < condition.getArguments().size(); i++) {
+                ILogicalExpression expr = 
condition.getArguments().get(i).getValue();
+                if 
(expr.getExpressionTag().equals(LogicalExpressionTag.FUNCTION_CALL)) {
+                    AbstractFunctionCallExpression AFCexpr = 
(AbstractFunctionCallExpression) expr;
+                    SkipSecondaryIndexSearchExpressionAnnotation skipAnno =
+                            
AFCexpr.getAnnotation(SkipSecondaryIndexSearchExpressionAnnotation.class);
+                    if (skipAnno != null) {
+                        return skipAnno;
+                    }
+                }
+            }
+        } else if 
(condition.getExpressionTag().equals(LogicalExpressionTag.FUNCTION_CALL)) {
+            SkipSecondaryIndexSearchExpressionAnnotation skipAnno =
+                    
condition.getAnnotation(SkipSecondaryIndexSearchExpressionAnnotation.class);
+            if (skipAnno != null) {
+                return skipAnno;
+            }
+        }
+        return null;
+    }
+
     protected int findJoinNodeIndexByName(String name) {
         for (int i = 1; i <= this.numberOfTerms; i++) {
             if (name.equals(jnArray[i].datasetNames.get(0))) {
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
index 4543190f27..37212bae7e 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
@@ -21,8 +21,10 @@ package org.apache.asterix.optimizer.rules.cbo;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -546,9 +548,20 @@ public class JoinNode {
         for (int i = 0; i < IndexCostInfo.size(); i++) {
             if (IndexCostInfo.get(i).second == -1.0) {
                 AbstractFunctionCallExpression afce = 
IndexCostInfo.get(i).third;
-                // this index has to be skipped, so find the corresponding 
expression
-                EnumerateJoinsRule.setAnnotation(afce, 
SkipSecondaryIndexSearchExpressionAnnotation
-                        
.newInstance(Collections.singleton(IndexCostInfo.get(i).first.getIndexName())));
+                SkipSecondaryIndexSearchExpressionAnnotation skipAnno = 
joinEnum.findSkipIndexHint(afce);
+                Collection<String> indexNames = new HashSet<>();
+                if (skipAnno != null && skipAnno.getIndexNames() != null) {
+                    indexNames.addAll(skipAnno.getIndexNames());
+                }
+                if (indexNames.isEmpty()) {
+                    // this index has to be skipped, so find the corresponding 
expression
+                    EnumerateJoinsRule.setAnnotation(afce, 
SkipSecondaryIndexSearchExpressionAnnotation
+                            
.newInstance(Collections.singleton(IndexCostInfo.get(i).first.getIndexName())));
+                } else {
+                    indexNames.add(IndexCostInfo.get(i).first.getIndexName());
+                    EnumerateJoinsRule.setAnnotation(afce,
+                            
SkipSecondaryIndexSearchExpressionAnnotation.newInstance(indexNames));
+                }
             }
         }
     }
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
index 254d36496d..785da69b66 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
@@ -446,33 +446,41 @@ public class Stats {
 
         List<List<IAObject>> result;
         parent.getInputs().get(0).setValue(deepCopyofScan);
-        if (numSubplans == 1 && nonSubplanSelects == 0) {
-            AggregateOperator aggOp = findAggOp(selOp, exp);
-            if (aggOp.getExpressions().size() > 1) {
-                // ANY and EVERY IN query; for selectivity purposes, we need 
to transform this into a ANY IN query
-                SelectOperator newSelOp = (SelectOperator) 
OperatorManipulationUtil.bottomUpCopyOperators(selOp);
-                aggOp = findAggOp(newSelOp, exp);
-                ILogicalOperator input = aggOp.getInputs().get(0).getValue();
-                SelectOperator condition = (SelectOperator) 
OperatorManipulationUtil
-                        
.bottomUpCopyOperators(AbstractOperatorFromSubplanRewrite.getSelectFromPlan(aggOp));
-                //push this condition below aggOp.
-                aggOp.getInputs().get(0).setValue(condition);
-                condition.getInputs().get(0).setValue(input);
-                ILogicalExpression newExp2 = 
newSelOp.getCondition().getValue();
-                if (newExp2.getExpressionTag() == 
LogicalExpressionTag.FUNCTION_CALL) {
-                    AbstractFunctionCallExpression afce = 
(AbstractFunctionCallExpression) newExp2;
-                    
afce.getArguments().get(1).setValue(ConstantExpression.TRUE);
+
+        if (numSelects == 1 && numSubplans == 0) { // just switch the 
predicates; the simplest case. There should be no other case if subplans were 
canonical
+            ILogicalExpression saveExprs = selOp.getCondition().getValue();
+            selOp.getCondition().setValue(exp);
+            result = runSamplingQuery(optCtx, selOp);
+            selOp.getCondition().setValue(saveExprs);
+        } else {
+            if (numSubplans == 1 && nonSubplanSelects == 0) {
+                AggregateOperator aggOp = findAggOp(selOp, exp);
+                if (aggOp.getExpressions().size() > 1) {
+                    // ANY and EVERY IN query; for selectivity purposes, we 
need to transform this into a ANY IN query
+                    SelectOperator newSelOp = (SelectOperator) 
OperatorManipulationUtil.bottomUpCopyOperators(selOp);
+                    aggOp = findAggOp(newSelOp, exp);
+                    ILogicalOperator input = 
aggOp.getInputs().get(0).getValue();
+                    SelectOperator condition = (SelectOperator) 
OperatorManipulationUtil
+                            
.bottomUpCopyOperators(AbstractOperatorFromSubplanRewrite.getSelectFromPlan(aggOp));
+                    //push this condition below aggOp.
+                    aggOp.getInputs().get(0).setValue(condition);
+                    condition.getInputs().get(0).setValue(input);
+                    ILogicalExpression newExp2 = 
newSelOp.getCondition().getValue();
+                    if (newExp2.getExpressionTag() == 
LogicalExpressionTag.FUNCTION_CALL) {
+                        AbstractFunctionCallExpression afce = 
(AbstractFunctionCallExpression) newExp2;
+                        
afce.getArguments().get(1).setValue(ConstantExpression.TRUE);
+                    }
+                    result = runSamplingQuery(optCtx, newSelOp); // no need to 
switch anything
+                } else {
+                    result = runSamplingQuery(optCtx, selOp);
                 }
-                result = runSamplingQuery(optCtx, newSelOp); // no need to 
switch anything
             } else {
+                SelectOperator selOp2 = findSelectOpWithExpr(selOp, exp);
+                List<ILogicalExpression> selExprs;
+                selExprs = storeSelectConditionsAndMakeThemTrue(selOp, 
selOp2); // all these will be marked true and will be resorted later.
                 result = runSamplingQuery(optCtx, selOp);
+                restoreAllSelectConditions(selOp, selExprs, selOp2);
             }
-        } else {
-            SelectOperator selOp2 = findSelectOpWithExpr(selOp, exp);
-            List<ILogicalExpression> selExprs;
-            selExprs = storeSelectConditionsAndMakeThemTrue(selOp, selOp2); // 
all these will be marked true and will be resorted later.
-            result = runSamplingQuery(optCtx, selOp);
-            restoreAllSelectConditions(selOp, selExprs, selOp2);
         }
 
         double predicateCardinality = findPredicateCardinality(result, false);
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/btree-index-selection/hints-use-index/hints-use-index-16.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/btree-index-selection/hints-use-index/hints-use-index-16.plan
index 00ba0d7ded..725e81e65f 100644
--- 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/btree-index-selection/hints-use-index/hints-use-index-16.plan
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/btree-index-selection/hints-use-index/hints-use-index-16.plan
@@ -9,11 +9,11 @@
                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                   -- BTREE_SEARCH (test.tenk.tenk)  |PARTITIONED|
                     -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                      -- STABLE_SORT [$$31(ASC)]  |PARTITIONED|
+                      -- STABLE_SORT [$$28(ASC)]  |PARTITIONED|
                         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                           -- STREAM_PROJECT  |PARTITIONED|
                             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                              -- BTREE_SEARCH (test.tenk.idx_1k_2k)  
|PARTITIONED|
+                              -- BTREE_SEARCH (test.tenk.idx_2k)  |PARTITIONED|
                                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                                   -- ASSIGN  |PARTITIONED|
                                     -- EMPTY_TUPLE_SOURCE  |PARTITIONED|

Reply via email to