[fix](nereids)select base index if mv's data type is different from base table (#27387)

normally, mv column's data type should be same as base table. This pr plays as a fail-safe, if mv column's data type is different from base table accidentally, fall back to select base table to make the query works.
This commit is contained in:
starocean999
2023-11-23 18:41:59 +08:00
committed by GitHub
parent d9f6e51884
commit 511eedb4ff

View File

@ -21,6 +21,7 @@ import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.KeysType;
import org.apache.doris.catalog.MaterializedIndex;
import org.apache.doris.catalog.OlapTable;
import org.apache.doris.catalog.PrimitiveType;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.rules.rewrite.RewriteRuleFactory;
@ -32,12 +33,14 @@ import org.apache.doris.nereids.trees.plans.PreAggStatus;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
import org.apache.doris.nereids.util.ExpressionUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@ -184,6 +187,11 @@ public class SelectMaterializedIndexWithoutAggregate extends AbstractSelectMater
default:
throw new RuntimeException("Not supported keys type: " + keysType);
}
Set<Slot> requiredSlots = new HashSet<>();
requiredSlots.addAll(requiredScanOutputSupplier.get());
requiredSlots.addAll(ExpressionUtils.getInputSlotSet(requiredExpr));
requiredSlots.addAll(ExpressionUtils.getInputSlotSet(predicatesSupplier.get()));
if (scan.getTable().isDupKeysOrMergeOnWrite()) {
// Set pre-aggregation to `on` to keep consistency with legacy logic.
List<MaterializedIndex> candidates = scan
@ -192,6 +200,9 @@ public class SelectMaterializedIndexWithoutAggregate extends AbstractSelectMater
scan, requiredScanOutputSupplier.get(), requiredExpr, predicatesSupplier.get()))
.collect(Collectors.toList());
long bestIndex = selectBestIndex(candidates, scan, predicatesSupplier.get());
// this is fail-safe for select mv
// select baseIndex if bestIndex's slots' data types are different from baseIndex
bestIndex = isSameDataType(scan, bestIndex, requiredSlots) ? bestIndex : baseIndexId;
return scan.withMaterializedIndexSelected(PreAggStatus.on(), bestIndex);
} else {
final PreAggStatus preAggStatus;
@ -219,12 +230,30 @@ public class SelectMaterializedIndexWithoutAggregate extends AbstractSelectMater
// `candidates` only have base index.
return scan.withMaterializedIndexSelected(preAggStatus, baseIndexId);
} else {
return scan.withMaterializedIndexSelected(preAggStatus,
selectBestIndex(candidates, scan, predicatesSupplier.get()));
long bestIndex = selectBestIndex(candidates, scan, predicatesSupplier.get());
// this is fail-safe for select mv
// select baseIndex if bestIndex's slots' data types are different from baseIndex
bestIndex = isSameDataType(scan, bestIndex, requiredSlots) ? bestIndex : baseIndexId;
return scan.withMaterializedIndexSelected(preAggStatus, bestIndex);
}
}
}
private boolean isSameDataType(LogicalOlapScan scan, long selectIndex, Set<Slot> slots) {
if (selectIndex != scan.getTable().getBaseIndexId()) {
Map<String, PrimitiveType> columnTypes =
scan.getTable().getSchemaByIndexId(selectIndex).stream().collect(Collectors
.toMap(Column::getNameWithoutMvPrefix, column -> column.getDataType()));
return slots.stream().allMatch(slot -> {
PrimitiveType dataType =
columnTypes.getOrDefault(slot.getName(), PrimitiveType.NULL_TYPE);
return dataType == PrimitiveType.NULL_TYPE
|| dataType == slot.getDataType().toCatalogDataType().getPrimitiveType();
});
}
return true;
}
private boolean indexHasAggregate(MaterializedIndex index, LogicalOlapScan scan) {
return scan.getTable().getSchemaByIndexId(index.getId())
.stream()