>From <[email protected]>:
[email protected] has uploaded this change for review. (
https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17491 )
Change subject: [ASTERIXDB-3167][COMP] Analytics CBO is choosing suboptimal
index paths
......................................................................
[ASTERIXDB-3167][COMP] Analytics CBO is choosing suboptimal index paths
Change-Id: I856b923d21e6c4e9bc7e65dd9043bdf17bfe502b
---
M
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java
1 file changed, 118 insertions(+), 0 deletions(-)
git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb
refs/changes/91/17491/1
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java
index f021845..b825986 100644
---
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java
@@ -26,10 +26,12 @@
import java.util.TreeMap;
import org.apache.asterix.algebra.operators.CommitOperator;
+import org.apache.asterix.common.config.DatasetConfig;
import org.apache.asterix.common.exceptions.CompilationException;
import org.apache.asterix.common.exceptions.ErrorCode;
import org.apache.asterix.metadata.declared.MetadataProvider;
import org.apache.asterix.metadata.entities.Index;
+import org.apache.asterix.metadata.utils.ArrayIndexUtil;
import
org.apache.asterix.optimizer.rules.am.array.IIntroduceAccessMethodRuleLocalRewrite;
import org.apache.asterix.optimizer.rules.am.array.MergedSelectRewrite;
import org.apache.asterix.optimizer.rules.am.array.SelectFromSubplanRewrite;
@@ -370,6 +372,112 @@
return lop;
}
+ // list1 is <= list2 in terms of size; so check if everything in list1 is
also in list2 in the same order
+ protected boolean prefix(List<List<String>> list1, List<List<String>>
list2) {
+ int i, j;
+
+ for (i = 0; i < list1.size(); i++) {
+ List<String> l1 = list1.get(i);
+ List<String> l2 = list2.get(i);
+ if (l1.size() != l2.size()) {
+ return false;
+ }
+ for (j = 0; j < l1.size(); j++) {
+ String s1 = l1.get(j);
+ String s2 = l2.get(j);
+ if (!(s1.equals(s2))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ // This code was lifted from AbstractIntroduceAccessMethodRule and
modified.
+ // Harder to refactor as the other code was also getting keyTypes
+ protected List<List<String>> findKeyFieldNames(Index index) throws
CompilationException {
+ List<List<String>> keyFieldNames;
+ DatasetConfig.IndexType indexType = index.getIndexType();
+ switch (Index.IndexCategory.of(indexType)) {
+ case ARRAY:
+ Index.ArrayIndexDetails arrayIndexDetails =
(Index.ArrayIndexDetails) index.getIndexDetails();
+ keyFieldNames = new ArrayList<>();
+
+ for (Index.ArrayIndexElement e :
arrayIndexDetails.getElementList()) {
+ for (int i = 0; i < e.getProjectList().size(); i++) {
+ List<String> project = e.getProjectList().get(i);
+
keyFieldNames.add(ArrayIndexUtil.getFlattenedKeyFieldNames(e.getUnnestList(),
project));
+ }
+ }
+ break;
+ case VALUE:
+ Index.ValueIndexDetails valueIndexDetails =
(Index.ValueIndexDetails) index.getIndexDetails();
+ keyFieldNames = valueIndexDetails.getKeyFieldNames();
+
+ break;
+ case TEXT:
+ Index.TextIndexDetails textIndexDetails =
(Index.TextIndexDetails) index.getIndexDetails();
+ keyFieldNames = textIndexDetails.getKeyFieldNames();
+
+ break;
+ default:
+ throw new
CompilationException(ErrorCode.COMPILATION_UNKNOWN_INDEX_TYPE,
String.valueOf(indexType));
+ }
+
+ return keyFieldNames;
+
+ }
+
+ protected void removeSmallerPrefixIndexes(List<Pair<IAccessMethod, Index>>
indexes) throws CompilationException {
+ int len = indexes.size();
+ int i, j;
+ Index index_i, index_j;
+ boolean include[];
+ include = new boolean[len];
+ for (i = 0; i < len; i++) {
+ include[i] = true; // Initially every index is included.
+ }
+
+ List<List<String>> fieldNames_i, fieldNames_j;
+
+ for (i = 0; i < len - 1; i++) {
+ if (include[i]) {
+ IAccessMethod ami = indexes.get(i).first;
+ index_i = indexes.get(i).second;
+ DatasetConfig.IndexType type_i = index_i.getIndexType();
+
+ fieldNames_i = findKeyFieldNames(index_i);
+
+ for (j = i + 1; j < len; j++) {
+ if (include[j]) {
+ IAccessMethod amj = indexes.get(j).first;
+ if (ami == amj) { // should be the same accessMethods
+ index_j = indexes.get(j).second;
+ DatasetConfig.IndexType type_j =
index_j.getIndexType();
+ if (type_i == type_j) {
+ fieldNames_j = findKeyFieldNames(index_j);
+ if (fieldNames_i.size() <=
fieldNames_j.size()) {
+ if (prefix(fieldNames_i, fieldNames_j)) {
+ include[i] = false;
+ }
+ } else if (prefix(fieldNames_j, fieldNames_i))
{
+ include[j] = false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // remove the shorter indexes if any
+ for (i = len - 1; i >= 0; i--) { // removing from the end; seems safer
that way
+ if (!include[i]) { // if this index can be removed it, do so;
+ indexes.remove(i);
+ }
+ }
+ }
+
/**
* Recursively traverse the given plan and check whether a SELECT operator
exists.
* If one is found, maintain the path from the root to SELECT operator and
@@ -484,6 +592,7 @@
// Choose all indexes that will be applied.
chooseAllIndexes(analyzedAMs, chosenIndexes);
+ removeSmallerPrefixIndexes(chosenIndexes);
if (chosenIndexes == null || chosenIndexes.isEmpty()) {
// We can't apply any index for this SELECT operator
--
To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17491
To unsubscribe, or for help writing mail filters, visit
https://asterix-gerrit.ics.uci.edu/settings
Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Change-Id: I856b923d21e6c4e9bc7e65dd9043bdf17bfe502b
Gerrit-Change-Number: 17491
Gerrit-PatchSet: 1
Gerrit-Owner: [email protected]
Gerrit-MessageType: newchange