foxtail463 commented on PR #63081:
URL: https://github.com/apache/doris/pull/63081#issuecomment-4407541860

   ## 问题
   
   在 MV union rewrite 过程中,`rewrittenPlanUsePartitionNameSet` 
可能包含一些**不在原始查询范围内**的 MV 分区。
   
   旧逻辑会把所有需要从 MV scan 中移除的分区都映射回 base table 分区,并加入 
`baseTableNeedUnionPartitionNameSet`。
   
   这样可能会生成不必要的 base table `UNION ALL` 分支,导致 MV candidate 的代价被高估,最终使一个本来可用的 MV 
改写结果出现在 `MaterializedViewRewriteSuccessButNotChose` 中。
   
   ## 示例
   
   假设有一张按日期分区的 base table:`sales`。
   
   ```text
   sales partitions:
   p20260301, p20260302, ..., p20260331,
   p20260401, p20260402, p20260403, ..., p20260428
   ```
   
   原始查询只需要读取 3 个 base table 分区:
   
   ```text
   queryUsedBaseTablePartitionNameSet =
   {p20260401, p20260402, p20260403}
   ```
   
   但是在 MV union rewrite 过程中,临时生成的 MV scan 可能会选择一个更大的分区范围:
   
   ```text
   rewrittenPlanUsePartitionNameSet =
   {p20260301, ..., p20260331, p20260401, p20260402, p20260403, ..., p20260428}
   ```
   
   假设当前有效的 MV 分区只有查询真正需要的这几个:
   
   ```text
   mvValidPartitionNameSet =
   {p20260401, p20260402, p20260403}
   ```
   
   那么需要从 MV scan 中移除的分区是:
   
   ```text
   mvNeedRemovePartitionNameSet =
       rewrittenPlanUsePartitionNameSet - mvValidPartitionNameSet
   
   = {
       p20260301, ..., p20260331,
       p20260404, ..., p20260428
     }
   ```
   
   这些被移除的 MV 分区都不在原始查询范围内。
   
   它们应该从 MV scan 中移除,但不应该再从 base table 中 union 回来,因为原始查询根本不需要这些分区。
   
   ## 这个 PR 之前
   
   旧逻辑会把所有映射出来的 base table 分区都加入 `baseTableNeedUnionPartitionNameSet`:
   
   ```java
   baseTableNeedUnionPartitionNameSet.addAll(baseTablePartitions);
   ```
   
   因此最终改写出来的计划可能逻辑上类似于:
   
   ```sql
   SELECT ...
   FROM mv_sales_daily
   WHERE dt IN ('2026-04-01', '2026-04-02', '2026-04-03')
   
   UNION ALL
   
   SELECT ...
   FROM sales
   WHERE dt IN (
       '2026-03-01', ..., '2026-03-31',
       '2026-04-04', ..., '2026-04-28'
   );
   ```
   
   第二个 `UNION ALL` 分支是不必要的,因为这些分区并不在原始查询范围内。
   
   这会带来两个问题:
   
   1. 生成了多余的 base table scan。
   2. MV candidate 的 cost 被放大,可能导致这个 MV 改写结果虽然成功了,但最终没有被选择。
   
   ## 这个 PR 之后
   
   这个 PR 会先取交集,只把原始查询真正用到的 base table 分区加入 `baseTableNeedUnionPartitionNameSet`:
   
   ```java
   baseTableNeedUnionPartitionNameSet.addAll(
           Sets.intersection(baseTablePartitions, 
queryUsedBaseTablePartitionNameSet));
   ```
   
   在上面的例子中:
   
   ```text
   baseTablePartitions =
   {
     p20260301, ..., p20260331,
     p20260404, ..., p20260428
   }
   
   queryUsedBaseTablePartitionNameSet =
   {
     p20260401, p20260402, p20260403
   }
   
   intersection =
   {}
   ```
   
   所以不会生成任何不必要的 base table union 分支。
   
   最终改写计划只需要:
   
   ```sql
   SELECT ...
   FROM mv_sales_daily
   WHERE dt IN ('2026-04-01', '2026-04-02', '2026-04-03');
   ```


-- 
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]

Reply via email to