[fix](join)join reorder by mistake (#12113)

This commit is contained in:
starocean999
2022-09-01 09:46:01 +08:00
committed by GitHub
parent f3cb0c24ee
commit d7e02a9514
4 changed files with 150 additions and 15 deletions

View File

@ -44,12 +44,24 @@ public class FromClause implements ParseNode, Iterable<TableRef> {
private boolean analyzed = false;
private boolean needToSql = false;
// the tables positions may be changed by 'join reorder' optimization
// after reset, the original order information is lost
// in the next re-analyze phase, the mis-ordered tables may lead to 'unable to find column xxx' error
// now we use originalTableRefOrders to keep track of table order information
// so that in reset method, we can recover the original table orders.
private final ArrayList<TableRef> originalTableRefOrders = new ArrayList<TableRef>();
public FromClause(List<TableRef> tableRefs) {
tablerefs = Lists.newArrayList(tableRefs);
// Set left table refs to ensure correct toSql() before analysis.
for (int i = 1; i < tablerefs.size(); ++i) {
tablerefs.get(i).setLeftTblRef(tablerefs.get(i - 1));
}
// save the tableRef's order, will use in reset method later
originalTableRefOrders.clear();
for (int i = 0; i < tablerefs.size(); ++i) {
originalTableRefOrders.add(tablerefs.get(i));
}
}
public FromClause() {
@ -129,6 +141,12 @@ public class FromClause implements ParseNode, Iterable<TableRef> {
changeTblRefToNullable(analyzer);
analyzed = true;
// save the tableRef's order, will use in reset method later
originalTableRefOrders.clear();
for (int i = 0; i < tablerefs.size(); ++i) {
originalTableRefOrders.add(tablerefs.get(i));
}
}
// set null-side inlinve view column
@ -154,13 +172,21 @@ public class FromClause implements ParseNode, Iterable<TableRef> {
for (TableRef tblRef : tablerefs) {
clone.add(tblRef.clone());
}
return new FromClause(clone);
FromClause result = new FromClause(clone);
for (int i = 0; i < clone.size(); ++i) {
result.originalTableRefOrders.add(clone.get(i));
}
return result;
}
public void reset() {
for (int i = 0; i < size(); ++i) {
get(i).reset();
}
// recover original table orders
for (int i = 0; i < size(); ++i) {
tablerefs.set(i, originalTableRefOrders.get(i));
}
this.analyzed = false;
}
@ -206,17 +232,32 @@ public class FromClause implements ParseNode, Iterable<TableRef> {
public void set(int i, TableRef tableRef) {
tablerefs.set(i, tableRef);
originalTableRefOrders.set(i, tableRef);
}
public void add(TableRef t) {
tablerefs.add(t);
// join reorder will call add method after call clear method.
// we want to keep tableRefPositions unchanged in that case
// in other cases, tablerefs.size() would larger than tableRefPositions.size()
// then we can update tableRefPositions. same logic in addAll method.
if (tablerefs.size() > originalTableRefOrders.size()) {
originalTableRefOrders.add(t);
}
}
public void addAll(List<TableRef> t) {
tablerefs.addAll(t);
if (tablerefs.size() > originalTableRefOrders.size()) {
for (int i = originalTableRefOrders.size(); i < tablerefs.size(); ++i) {
originalTableRefOrders.add(tablerefs.get(i));
}
}
}
public void clear() {
// this method on be called in reorder table
// we want to keep tableRefPositions, only clear tablerefs
tablerefs.clear();
}
}

View File

@ -733,12 +733,12 @@ public class SelectStmt extends QueryStmt {
protected void reorderTable(Analyzer analyzer) throws AnalysisException {
List<Pair<TableRef, Long>> candidates = Lists.newArrayList();
List<TableRef> originOrderBackUp = Lists.newArrayList(fromClause.getTableRefs());
ArrayList<TableRef> originOrderBackUp = Lists.newArrayList(fromClause.getTableRefs());
// New pair of table ref and row count
for (TableRef tblRef : fromClause) {
if (tblRef.getJoinOp() != JoinOperator.INNER_JOIN || tblRef.hasJoinHints()) {
// Unsupported reorder outer join
return;
break;
}
long rowCount = 0;
if (tblRef.getTable().getType() == TableType.OLAP) {
@ -747,6 +747,11 @@ public class SelectStmt extends QueryStmt {
}
candidates.add(Pair.of(tblRef, rowCount));
}
int reorderTableCount = candidates.size();
if (reorderTableCount < originOrderBackUp.size()) {
fromClause.clear();
fromClause.addAll(originOrderBackUp.subList(0, reorderTableCount));
}
// give InlineView row count
long last = 0;
for (int i = candidates.size() - 1; i >= 0; --i) {
@ -765,6 +770,9 @@ public class SelectStmt extends QueryStmt {
// as long as one scheme success, we return this scheme immediately.
// in this scheme, candidate.first will be consider to be the big table in star schema.
// this scheme might not be fit for snowflake schema.
if (reorderTableCount < originOrderBackUp.size()) {
fromClause.addAll(originOrderBackUp.subList(reorderTableCount, originOrderBackUp.size()));
}
return;
}
}
@ -819,18 +827,7 @@ public class SelectStmt extends QueryStmt {
List<Expr> candidateEqJoinPredicates = analyzer.getEqJoinConjunctsExcludeAuxPredicates(tid);
for (Expr candidateEqJoinPredicate : candidateEqJoinPredicates) {
List<TupleId> candidateTupleList = Lists.newArrayList();
List<Expr> candidateEqJoinPredicateList = Lists.newArrayList(candidateEqJoinPredicate);
// If a large table or view has joinClause is ranked first,
// and the joinClause is not judged here,
// the column in joinClause may not be found during reanalyzing.
// for example:
// select * from t1 inner join t2 on t1.a = t2.b inner join t3 on t3.c = t2.b;
// If t3 is a large table, it will be placed first after the reorderTable,
// and the problem that t2.b does not exist will occur in reanalyzing
if (candidateTableRef.getOnClause() != null) {
candidateEqJoinPredicateList.add(candidateTableRef.getOnClause());
}
Expr.getIds(candidateEqJoinPredicateList, candidateTupleList, null);
Expr.getIds(Lists.newArrayList(candidateEqJoinPredicate), candidateTupleList, null);
int count = candidateTupleList.size();
for (TupleId tupleId : candidateTupleList) {
if (validTupleId.contains(tupleId) || tid.equals(tupleId)) {