github-actions[bot] commented on code in PR #68648:
URL: https://github.com/apache/doris/pull/68648#discussion_r4145157487
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/UpdateMvByPartitionCommand.java:
##########
@@ -350,10 +555,33 @@ public Plan
visitLogicalCatalogRelation(LogicalCatalogRelation catalogRelation,
predicates.setNeedAddFilter(false);
}
if (!partitionHasDataItems.isEmpty()) {
+ // The partitions are pinned the way a refresh pins
them: the whole key of each, at
+ // the partition column's own type. A predicate on the
MV's partition column alone
+ // reads the partitions that differ in the other keys
too, and those rows are ones
+ // this branch must not add -- the MV branch of the
union already supplies them, or
+ // the compensation would count them twice -- while a
key written with a scale has to
+ // be compared at that scale or its rows are read as
none.
+ // A list partitioned table's default partition is not
pinned the way the others
+ // are: its own key is the sentinel the rows no other
partition claims were placed
+ // by, so pinning it to that key reads none of them.
It is read the way it was
+ // before the whole key was pinned -- on the MV's
partition column alone -- which
+ // can be seen to be too wide rather than one that
drops its rows.
+ boolean hasDefaultPartition =
partitionHasDataItems.stream()
+ .anyMatch(PartitionItem::isDefaultPartition);
+ Set<Expression> mvPartitionPredicates =
hasDefaultPartition
+ ? mvPartitionsToReadThrough(predicates,
relatedTableColumnInfo, partitionSlot)
+ : Sets.newHashSet();
+ Set<Expression> preds;
+ if (!mvPartitionPredicates.isEmpty()) {
+ preds = mvPartitionPredicates;
+ } else if (targetTable instanceof OlapTable &&
!hasDefaultPartition) {
+ preds =
constructPredicatesOfBasePartitions(partitionHasDataItems,
+ (OlapTable) targetTable,
relatedTableColumnInfo.getColName());
Review Comment:
[P2] Bind base partition slots in union compensation. When one RANGE or LIST
MV partition is stale and another is valid, this branch applies the full-tuple
predicate to an already bound LogicalCatalogRelation, but the helper creates
UnboundSlot values. The following whole-tree rewrite has no binding pass;
CheckAfterRewrite throws UnboundException, which the MV rule catches and
records as a failed candidate. Thus partial union rewrites over nondefault OLAP
partitions fall back to base scans. Resolve the tuple columns from
catalogRelation.getOutput() here.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/UpdateMvByPartitionCommand.java:
##########
@@ -284,6 +440,55 @@ public Plan
visitLogicalSubQueryAlias(LogicalSubQueryAlias<? extends Plan> subQu
return super.visitLogicalSubQueryAlias(subQueryAlias, predicates);
}
+ /**
+ * The ranges of the MV partitions this compensation removes, as a
predicate on the base table's
+ * partition column, or nothing when they cannot be written on one
column.
+ *
+ * <p>A default partition's rows belong to whichever MV partition
their own key falls in, so this is
+ * what they are read through: pinning them to the partition's own key
-- the sentinel those rows were
+ * placed by -- reads none of them, and reading them whole would add
the rows of the MV partitions the
+ * plan still has. Only an MV partitioned by this one column can be
written that way here.
+ */
+ private static Set<Expression>
mvPartitionsToReadThrough(PredicateAddContext predicates,
+ BaseColInfo relatedTableColumnInfo, Slot partitionSlot) {
+ Set<Expression> res = Sets.newHashSet();
+ if (predicates.getMvPartitionsToRemove().isEmpty()) {
+ return res;
+ }
+ for (Map.Entry<BaseTableInfo, Set<String>> entry
+ : predicates.getMvPartitionsToRemove().entrySet()) {
+ try {
+ TableIf table = MTMVUtil.getTable(entry.getKey());
+ if (!(table instanceof MTMV)) {
+ continue;
+ }
+ MTMV mtmv = (MTMV) table;
+ if (mtmv.getPartitionColumns().size() != 1
+ || !mtmv.getPartitionColumns().get(0).getName()
+
.equalsIgnoreCase(relatedTableColumnInfo.getColName())) {
+ continue;
+ }
+ Type columnType =
mtmv.getPartitionColumns().get(0).getType();
+ for (String partitionName : entry.getValue()) {
+ PartitionItem item =
mtmv.getPartitionItemOrAnalysisException(partitionName);
+ if (!(item instanceof ListPartitionItem)) {
+ continue;
+ }
+ List<Expression> values = ((ListPartitionItem)
item).getItems().stream()
+ .map(key -> convertPartitionKeyToLiteral(key,
0, Optional.of(columnType)))
+ .collect(Collectors.toList());
+ res.add(new InPredicate(partitionSlot, values));
+ }
Review Comment:
[P1] Preserve NULL keys in default-partition compensation. When a nullable
LIST(k) MV has a stale NULL partition and a valid k=1 partition, its default
base partition makes this helper filter the removed NULL partition as k IN
(NULL). That predicate is UNKNOWN even for NULL rows, so the union base branch
omits committed rows from p_null. Use the NULL-aware list conversion below,
which emits k IS NULL, and cover the partial-union case.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/RefreshMTMVCommand.java:
##########
@@ -198,8 +198,11 @@ protected LogicalPlan createRefreshCommand(MTMV mtmv,
StatementContext statement
statementContext.setIvmRewriteContext(Optional.of(IvmRewriteContext.fullExplain(mtmv)));
}
statementContext.setExcludedTriggerTables(mtmv.getExcludedTriggerTables());
+ // Explained through the MV partitions' own key ranges: the
read a refresh narrows to its
+ // partition mapping is decided by that refresh's context,
which a plan built here has not.
return UpdateMvByPartitionCommand.from(
- mtmv, getCompleteRefreshPartitions(mtmv),
getIncrementalTableMap(mtmv), statementContext);
+ mtmv, getCompleteRefreshPartitions(mtmv),
getIncrementalTableMap(mtmv), statementContext,
+ null);
Review Comment:
[P2] Explain the same base-partition scope as the refresh. With
partition_sync_limit, an expired base day can lie inside a retained MV year.
Actual COMPLETE refresh passes mappedBasePartitions and excludes that day, but
this null scope makes EXPLAIN REFRESH COMPLETE use the whole MV-year predicate
and show the expired partition as scanned. Build the explain predicate from the
same mapping so the plan describes the refresh it previews.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]