This is an automated email from the ASF dual-hosted git repository.

xy720 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 28c63a4809d [fix](profile) Nereids Optimize Time shows N/A when MV 
pre-rewrite is skipped (#67532)
28c63a4809d is described below

commit 28c63a4809dabc4adc2b8b4de1d3099b53c5a2de
Author: xy720 <[email protected]>
AuthorDate: Mon Sep 7 22:12:27 2026 +0800

    [fix](profile) Nereids Optimize Time shows N/A when MV pre-rewrite is 
skipped (#67532)
    
    `getPrettyNereidsOptimizeTime` computes the elapsed time as
    `optimizeFinish - preRewriteByMvFinish`,
    
    But `preRewriteByMvFinish` is only set at the tail of
    `preMaterializedViewRewrite`, which early-exits whenever pre-rewrite is
    not needed.
    
    The start marker stays at -1, `getPrettyTime` sees -1 and returns "N/A"
    — even though CBO did run and `optimizeFinish` is set.
    
    This misleads users on any query that skips MV pre-rewrite:
    1.MV refresh,
    2.INSERT, large joins using DpHyper,
    3.Sessions with `enable_materialized_view_rewrite=false`,
    4.Queries that don't touch any MV at all
    
    Example:
    an MV refresh with
    `Rewrite Time: 4ms`,
    `Translate Time:239ms`
    still prints `Optimize Time: N/A`, misleading anyone reading the profile
    into thinking CBO was skipped.
    
    Fall back the start marker through earlier phase finish times
    (`preRewriteByMv -> collectTablePartition -> rewrite`) so the elapsed
    time is shown whenever the upstream phase actually finished.
---
 .../doris/common/profile/SummaryProfile.java       |  12 ++-
 .../org/apache/doris/nereids/NereidsPlanner.java   | 114 +++++++++++----------
 .../doris/common/profile/SummaryProfileTest.java   |  46 +++++++++
 3 files changed, 114 insertions(+), 58 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/common/profile/SummaryProfile.java 
b/fe/fe-core/src/main/java/org/apache/doris/common/profile/SummaryProfile.java
index d2f6aea5992..0a595d0fbfe 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/common/profile/SummaryProfile.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/common/profile/SummaryProfile.java
@@ -945,7 +945,10 @@ public class SummaryProfile {
     }
 
     public int getNereidsOptimizeTimeMs() {
-        return getTimeMs(nereidsOptimizeFinishTime, 
nereidsCollectTablePartitionFinishTime);
+        long start = nereidsCollectTablePartitionFinishTime != -1
+                ? nereidsCollectTablePartitionFinishTime
+                : nereidsRewriteFinishTime;
+        return getTimeMs(nereidsOptimizeFinishTime, start);
     }
 
     public int getNereidsTranslateTimeMs() {
@@ -1050,7 +1053,12 @@ public class SummaryProfile {
     }
 
     public String getPrettyNereidsOptimizeTime() {
-        return getPrettyTime(nereidsOptimizeFinishTime, 
nereidsPreRewriteByMvFinishTime, TUnit.TIME_MS);
+        long start = nereidsPreRewriteByMvFinishTime != -1
+                ? nereidsPreRewriteByMvFinishTime
+                : (nereidsCollectTablePartitionFinishTime != -1
+                        ? nereidsCollectTablePartitionFinishTime
+                        : nereidsRewriteFinishTime);
+        return getPrettyTime(nereidsOptimizeFinishTime, start, TUnit.TIME_MS);
     }
 
     public String getPrettyNereidsTranslateTime() {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java
index 09c8ecd1d9c..1053699fff0 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java
@@ -536,64 +536,66 @@ public class NereidsPlanner extends Planner {
         if (!cascadesContext.getStatementContext().isNeedPreMvRewrite()) {
             return;
         }
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("Start pre rewrite plan by mv");
-        }
-        List<Plan> tmpPlansForMvRewrite = 
cascadesContext.getStatementContext().getTmpPlanForMvRewrite();
-        Plan originalPlan = cascadesContext.getRewritePlan();
-        List<Plan> plansWhichContainMv = new ArrayList<>();
-        // because tmpPlansForMvRewrite only one, so timeout is cumulative 
which is ok
-        for (Plan planForRewrite : tmpPlansForMvRewrite) {
-            SessionVariable sessionVariable = 
cascadesContext.getConnectContext()
-                    .getSessionVariable();
-            int timeoutSecond = sessionVariable.nereidsTimeoutSecond;
-            boolean enableTimeout = sessionVariable.enableNereidsTimeout;
-            try {
-                // set mv rewrite timeout
-                sessionVariable.nereidsTimeoutSecond = 
PreMaterializedViewRewriter.convertMillisToCeilingSeconds(
-                                
sessionVariable.materializedViewRewriteDurationThresholdMs);
-                sessionVariable.enableNereidsTimeout = true;
-                // pre rewrite
-                Plan rewrittenPlan = 
MaterializedViewUtils.rewriteByRules(cascadesContext,
-                        PreMaterializedViewRewriter::rewrite, planForRewrite, 
planForRewrite, true);
-                Plan ruleOptimizedPlan = 
MaterializedViewUtils.rewriteByRules(cascadesContext,
-                        childOptContext -> {
-                            
Rewriter.getWholeTreeRewriterWithoutCostBasedJobs(childOptContext).execute();
-                            return childOptContext.getRewritePlan();
-                        }, rewrittenPlan, planForRewrite, false);
-                if (ruleOptimizedPlan == null) {
-                    continue;
-                }
-                // after rbo, maybe the plan changed a lot, so we need to 
normalize it with original plan
-                Plan normalizedPlan = 
MaterializedViewUtils.normalizeSinkExpressions(
-                        ruleOptimizedPlan, originalPlan);
-                if (normalizedPlan != null) {
-                    plansWhichContainMv.add(normalizedPlan);
-                }
-            } catch (Exception e) {
-                LOG.error("pre mv rewrite in rbo rewrite fail, query id is {}",
-                        
cascadesContext.getConnectContext().getQueryIdentifier(), e);
+        try {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Start pre rewrite plan by mv");
+            }
+            List<Plan> tmpPlansForMvRewrite = 
cascadesContext.getStatementContext().getTmpPlanForMvRewrite();
+            Plan originalPlan = cascadesContext.getRewritePlan();
+            List<Plan> plansWhichContainMv = new ArrayList<>();
+            // because tmpPlansForMvRewrite only one, so timeout is cumulative 
which is ok
+            for (Plan planForRewrite : tmpPlansForMvRewrite) {
+                SessionVariable sessionVariable = 
cascadesContext.getConnectContext()
+                        .getSessionVariable();
+                int timeoutSecond = sessionVariable.nereidsTimeoutSecond;
+                boolean enableTimeout = sessionVariable.enableNereidsTimeout;
+                try {
+                    // set mv rewrite timeout
+                    sessionVariable.nereidsTimeoutSecond = 
PreMaterializedViewRewriter.convertMillisToCeilingSeconds(
+                                    
sessionVariable.materializedViewRewriteDurationThresholdMs);
+                    sessionVariable.enableNereidsTimeout = true;
+                    // pre rewrite
+                    Plan rewrittenPlan = 
MaterializedViewUtils.rewriteByRules(cascadesContext,
+                            PreMaterializedViewRewriter::rewrite, 
planForRewrite, planForRewrite, true);
+                    Plan ruleOptimizedPlan = 
MaterializedViewUtils.rewriteByRules(cascadesContext,
+                            childOptContext -> {
+                                
Rewriter.getWholeTreeRewriterWithoutCostBasedJobs(childOptContext).execute();
+                                return childOptContext.getRewritePlan();
+                            }, rewrittenPlan, planForRewrite, false);
+                    if (ruleOptimizedPlan == null) {
+                        continue;
+                    }
+                    // after rbo, maybe the plan changed a lot, so we need to 
normalize it with original plan
+                    Plan normalizedPlan = 
MaterializedViewUtils.normalizeSinkExpressions(
+                            ruleOptimizedPlan, originalPlan);
+                    if (normalizedPlan != null) {
+                        plansWhichContainMv.add(normalizedPlan);
+                    }
+                } catch (Exception e) {
+                    LOG.error("pre mv rewrite in rbo rewrite fail, query id is 
{}",
+                            
cascadesContext.getConnectContext().getQueryIdentifier(), e);
 
-            } finally {
-                sessionVariable.nereidsTimeoutSecond = timeoutSecond;
-                sessionVariable.enableNereidsTimeout = enableTimeout;
+                } finally {
+                    sessionVariable.nereidsTimeoutSecond = timeoutSecond;
+                    sessionVariable.enableNereidsTimeout = enableTimeout;
+                }
+            }
+            // clear the rewritten plans which are tmp optimized, should be 
filled by full optimize later
+            statementContext.getRewrittenPlansByMv().clear();
+            // if rule-based optimized, would not be rewritten by cbo, so 
clear materialized hooks
+            this.cascadesContext.getStatementContext().setPreMvRewritten(true);
+            if (!plansWhichContainMv.isEmpty()) {
+                
plansWhichContainMv.forEach(statementContext::addRewrittenPlanByMv);
+            }
+            NereidsTracer.logImportantTime("EndPreRewritePlanByMv");
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("End pre rewrite plan by mv");
+            }
+        } finally {
+            if (statementContext.getConnectContext().getExecutor() != null) {
+                
statementContext.getConnectContext().getExecutor().getSummaryProfile()
+                        
.setNereidsPreRewriteByMvFinishTime(TimeUtils.getStartTimeMs());
             }
-        }
-        // clear the rewritten plans which are tmp optimized, should be filled 
by full optimize later
-        statementContext.getRewrittenPlansByMv().clear();
-        // if rule-based optimized, would not be rewritten by cbo, so clear 
materialized hooks
-        this.cascadesContext.getStatementContext().setPreMvRewritten(true);
-        if (plansWhichContainMv.isEmpty()) {
-            return;
-        }
-        plansWhichContainMv.forEach(statementContext::addRewrittenPlanByMv);
-        NereidsTracer.logImportantTime("EndPreRewritePlanByMv");
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("End pre rewrite plan by mv");
-        }
-        if (statementContext.getConnectContext().getExecutor() != null) {
-            
statementContext.getConnectContext().getExecutor().getSummaryProfile()
-                    
.setNereidsPreRewriteByMvFinishTime(TimeUtils.getStartTimeMs());
         }
     }
 
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/common/profile/SummaryProfileTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/common/profile/SummaryProfileTest.java
index f6e8d5a677d..001d63364fc 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/common/profile/SummaryProfileTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/common/profile/SummaryProfileTest.java
@@ -131,4 +131,50 @@ public class SummaryProfileTest {
                 SummaryProfile.EXTERNAL_TABLE_GET_FILE_SCAN_TASKS_TIME));
         Assertions.assertEquals(28, profile.getExternalCatalogMetaTimeMs());
     }
+
+    @Test
+    public void testOptimizeTimeFallbackWhenPreMvSkipped() {
+        SummaryProfile profile = new SummaryProfile();
+        profile.setQueryBeginTime(1);
+        profile.setParseSqlStartTime(3);
+        profile.setParseSqlFinishTime(6);
+        profile.setNereidsLockTableStartTime(8);
+        profile.setNereidsLockTableFinishTime(10);
+        profile.setNereidsAnalysisTime(15);
+        profile.setNereidsRewriteTime(21);
+        profile.setNereidsOptimizeTime(36);
+        profile.setNereidsTranslateTime(45);
+        profile.setNereidsDistributeTime(55);
+        profile.setQueryPlanFinishTime(66);
+
+        profile.update(ImmutableMap.of());
+        RuntimeProfile executionSummary = profile.getExecutionSummary();
+
+        Assertions.assertEquals("N/A", 
executionSummary.getInfoString(SummaryProfile.NEREIDS_PRE_REWRITE_BY_MV_TIME));
+        Assertions.assertEquals("15ms", 
executionSummary.getInfoString(SummaryProfile.NEREIDS_OPTIMIZE_TIME));
+        Assertions.assertEquals(15, profile.getNereidsOptimizeTimeMs());
+    }
+
+    @Test
+    public void testPreMvAttemptedButEmpty() {
+        SummaryProfile profile = new SummaryProfile();
+        profile.setQueryBeginTime(1);
+        profile.setParseSqlStartTime(3);
+        profile.setParseSqlFinishTime(6);
+        profile.setNereidsLockTableStartTime(8);
+        profile.setNereidsLockTableFinishTime(10);
+        profile.setNereidsAnalysisTime(15);
+        profile.setNereidsRewriteTime(21);
+        profile.setNereidsCollectTablePartitionFinishTime(28);
+        profile.setNereidsPreRewriteByMvFinishTime(58);
+        profile.setNereidsOptimizeTime(60);
+        profile.setNereidsTranslateTime(65);
+
+        profile.update(ImmutableMap.of());
+        RuntimeProfile executionSummary = profile.getExecutionSummary();
+
+        Assertions.assertEquals("30ms", 
executionSummary.getInfoString(SummaryProfile.NEREIDS_PRE_REWRITE_BY_MV_TIME));
+        Assertions.assertEquals("2ms", 
executionSummary.getInfoString(SummaryProfile.NEREIDS_OPTIMIZE_TIME));
+        Assertions.assertEquals(32, profile.getNereidsOptimizeTimeMs());
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to