-
Notifications
You must be signed in to change notification settings - Fork 3.7k
[opt](mtmv) optimize mtmv rewrite performance #49514
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3333d82
f59f258
2198e6b
739cc22
92a580f
2e9d5b4
f330b23
d2fccea
fee2c4d
b62c3fd
5077f36
53e9377
a1673d4
537213f
170618c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,12 +25,16 @@ | |
| import org.apache.doris.qe.ConnectContext; | ||
|
|
||
| import com.google.common.collect.Lists; | ||
| import com.google.common.collect.Maps; | ||
| import com.google.common.collect.Sets; | ||
| import org.apache.logging.log4j.LogManager; | ||
| import org.apache.logging.log4j.Logger; | ||
|
|
||
| import java.util.Collection; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Map.Entry; | ||
| import java.util.Set; | ||
|
|
||
| public class MTMVRewriteUtil { | ||
| private static final Logger LOG = LogManager.getLogger(MTMVRewriteUtil.class); | ||
|
|
@@ -43,7 +47,8 @@ public class MTMVRewriteUtil { | |
| * @return | ||
| */ | ||
| public static Collection<Partition> getMTMVCanRewritePartitions(MTMV mtmv, ConnectContext ctx, | ||
| long currentTimeMills, boolean forceConsistent) { | ||
| long currentTimeMills, boolean forceConsistent, | ||
| Set<String> relatedPartitions) { | ||
| List<Partition> res = Lists.newArrayList(); | ||
| Collection<Partition> allPartitions = mtmv.getPartitions(); | ||
| MTMVRelation mtmvRelation = mtmv.getRelation(); | ||
|
|
@@ -55,6 +60,11 @@ public static Collection<Partition> getMTMVCanRewritePartitions(MTMV mtmv, Conne | |
| if (mtmvStatus.getState() != MTMVState.NORMAL || mtmvStatus.getRefreshState() == MTMVRefreshState.INIT) { | ||
| return res; | ||
| } | ||
| // if relatedPartitions is empty but not null, which means query no partitions | ||
| if (relatedPartitions != null && relatedPartitions.size() == 0) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add some comments to explain that if it is null, it means that all partitions need to be calculated, and if size is 0, it means that no partition needs to participate
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed, add more comment |
||
| return res; | ||
| } | ||
| Set<String> mtmvNeedComparePartitions = null; | ||
| MTMVRefreshContext refreshContext = null; | ||
| // check gracePeriod | ||
| long gracePeriodMills = mtmv.getGracePeriod(); | ||
|
|
@@ -73,6 +83,14 @@ public static Collection<Partition> getMTMVCanRewritePartitions(MTMV mtmv, Conne | |
| return res; | ||
| } | ||
| } | ||
| if (mtmvNeedComparePartitions == null) { | ||
| mtmvNeedComparePartitions = getMtmvPartitionsByRelatedPartitions(mtmv, refreshContext, | ||
| relatedPartitions); | ||
| } | ||
| // if the partition which query not used, should not compare partition version | ||
| if (!mtmvNeedComparePartitions.contains(partition.getName())) { | ||
| continue; | ||
| } | ||
| try { | ||
| if (MTMVPartitionUtil.isMTMVPartitionSync(refreshContext, partition.getName(), | ||
| mtmvRelation.getBaseTablesOneLevel(), | ||
|
|
@@ -86,4 +104,29 @@ public static Collection<Partition> getMTMVCanRewritePartitions(MTMV mtmv, Conne | |
| } | ||
| return res; | ||
| } | ||
|
|
||
| private static Set<String> getMtmvPartitionsByRelatedPartitions(MTMV mtmv, MTMVRefreshContext refreshContext, | ||
| Set<String> relatedPartitions) { | ||
| // if relatedPartitions is null, which means QueryPartitionCollector visitLogicalCatalogRelation can not | ||
| // get query used partitions, should get all mtmv partitions | ||
| if (relatedPartitions == null) { | ||
| return mtmv.getPartitionNames(); | ||
| } | ||
| Set<String> res = Sets.newHashSet(); | ||
| Map<String, String> relatedToMv = getRelatedToMv(refreshContext.getPartitionMappings()); | ||
| for (String relatedPartition : relatedPartitions) { | ||
| res.add(relatedToMv.get(relatedPartition)); | ||
| } | ||
| return res; | ||
| } | ||
|
|
||
| private static Map<String, String> getRelatedToMv(Map<String, Set<String>> mvToRelated) { | ||
| Map<String, String> res = Maps.newHashMap(); | ||
| for (Entry<String, Set<String>> entry : mvToRelated.entrySet()) { | ||
| for (String relatedPartition : entry.getValue()) { | ||
| res.put(relatedPartition, entry.getKey()); | ||
| } | ||
| } | ||
| return res; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -371,6 +371,21 @@ protected void collectAndLockTable(boolean showPlanProcess) { | |
| } | ||
| } | ||
|
|
||
| protected void collectTableUsedPartitions(boolean showPlanProcess) { | ||
| if (LOG.isDebugEnabled()) { | ||
| LOG.debug("Start to collect table used partition"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should log queryId?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the same to org.apache.doris.nereids.NereidsPlanner#analyze, i think should not add |
||
| } | ||
| keepOrShowPlanProcess(showPlanProcess, () -> cascadesContext.newTablePartitionCollector().execute()); | ||
| NereidsTracer.logImportantTime("EndCollectTablePartitions"); | ||
| if (LOG.isDebugEnabled()) { | ||
| LOG.debug("Start to collect table used partition"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the same to org.apache.doris.nereids.NereidsPlanner#analyze, i think should not add |
||
| } | ||
| if (statementContext.getConnectContext().getExecutor() != null) { | ||
| statementContext.getConnectContext().getExecutor().getSummaryProfile() | ||
| .setNereidsCollectTablePartitionFinishTime(); | ||
| } | ||
| } | ||
|
|
||
| protected void analyze(boolean showPlanProcess) { | ||
| if (LOG.isDebugEnabled()) { | ||
| LOG.debug("Start analyze plan"); | ||
|
|
@@ -403,6 +418,10 @@ protected void rewrite(boolean showPlanProcess) { | |
| if (statementContext.getConnectContext().getExecutor() != null) { | ||
| statementContext.getConnectContext().getExecutor().getSummaryProfile().setNereidsRewriteTime(); | ||
| } | ||
| // collect partitions table used, this is for query rewrite by materialized view | ||
| // this is needed before init hook | ||
| collectTableUsedPartitions(showPlanProcess); | ||
| cascadesContext.getStatementContext().getPlannerHooks().forEach(hook -> hook.afterRewrite(this)); | ||
| } | ||
|
|
||
| // DependsRules: EnsureProjectOnTopJoin.class | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |
| import org.apache.doris.analysis.StatementBase; | ||
| import org.apache.doris.analysis.TableSnapshot; | ||
| import org.apache.doris.catalog.Column; | ||
| import org.apache.doris.catalog.Partition; | ||
| import org.apache.doris.catalog.TableIf; | ||
| import org.apache.doris.catalog.View; | ||
| import org.apache.doris.catalog.constraint.TableIdentifier; | ||
|
|
@@ -30,6 +31,7 @@ | |
| import org.apache.doris.datasource.mvcc.MvccSnapshot; | ||
| import org.apache.doris.datasource.mvcc.MvccTable; | ||
| import org.apache.doris.datasource.mvcc.MvccTableInfo; | ||
| import org.apache.doris.mtmv.BaseTableInfo; | ||
| import org.apache.doris.nereids.exceptions.AnalysisException; | ||
| import org.apache.doris.nereids.hint.Hint; | ||
| import org.apache.doris.nereids.hint.UseMvHint; | ||
|
|
@@ -62,6 +64,7 @@ | |
| import com.google.common.base.Supplier; | ||
| import com.google.common.base.Suppliers; | ||
| import com.google.common.base.Throwables; | ||
| import com.google.common.collect.HashMultimap; | ||
| import com.google.common.collect.ImmutableList; | ||
| import com.google.common.collect.Maps; | ||
| import com.google.common.collect.Multimap; | ||
|
|
@@ -108,6 +111,7 @@ public enum TableFrom { | |
| private ConnectContext connectContext; | ||
|
|
||
| private final Stopwatch stopwatch = Stopwatch.createUnstarted(); | ||
| private final Stopwatch materializedViewStopwatch = Stopwatch.createUnstarted(); | ||
|
|
||
| @GuardedBy("this") | ||
| private final Map<String, Supplier<Object>> contextCacheMap = Maps.newLinkedHashMap(); | ||
|
|
@@ -176,7 +180,14 @@ public enum TableFrom { | |
|
|
||
| // tables in this query directly | ||
| private final Map<List<String>, TableIf> tables = Maps.newHashMap(); | ||
| // tables maybe used by mtmv rewritten in this query | ||
| // tables maybe used by mtmv rewritten in this query, | ||
| // this contains mvs which use table in tables and the tables in mvs | ||
| // such as | ||
| // mv1 use t1, t2. | ||
| // mv2 use mv1, t3, t4. | ||
| // mv3 use t3, t4, t5 | ||
| // if query is: select * from t2 join t5 | ||
| // mtmvRelatedTables is mv1, mv2, mv3, t1, t2, t3, t4, t5 | ||
| private final Map<List<String>, TableIf> mtmvRelatedTables = Maps.newHashMap(); | ||
| // insert into target tables | ||
| private final Map<List<String>, TableIf> insertTargetTables = Maps.newHashMap(); | ||
|
|
@@ -216,6 +227,16 @@ public enum TableFrom { | |
|
|
||
| private boolean privChecked; | ||
|
|
||
| // if greater than 0 means the duration has used | ||
| private long materializedViewRewriteDuration = 0L; | ||
|
|
||
| // Record used table and it's used partitions | ||
| private final Multimap<List<String>, Pair<RelationId, Set<String>>> tableUsedPartitionNameMap = | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not use List+RelationId as key
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in the later, would get by List which is table qualifier, so the key is List |
||
| HashMultimap.create(); | ||
|
|
||
| // Record mtmv and valid partitions map because this is time-consuming behavior | ||
| private final Map<BaseTableInfo, Collection<Partition>> mvCanRewritePartitionsMap = new HashMap<>(); | ||
|
|
||
| /// for dictionary sink. | ||
| private List<Backend> usedBackendsDistributing; // report used backends after done distribute planning. | ||
| private long dictionaryUsedSrcVersion; // base table data version used in this refreshing. | ||
|
|
@@ -361,6 +382,18 @@ public Stopwatch getStopwatch() { | |
| return stopwatch; | ||
| } | ||
|
|
||
| public Stopwatch getMaterializedViewStopwatch() { | ||
| return materializedViewStopwatch; | ||
| } | ||
|
|
||
| public long getMaterializedViewRewriteDuration() { | ||
| return materializedViewRewriteDuration; | ||
| } | ||
|
|
||
| public void addMaterializedViewRewriteDuration(long millisecond) { | ||
| materializedViewRewriteDuration += millisecond; | ||
| } | ||
|
|
||
| public void setMaxNAryInnerJoin(int maxNAryInnerJoin) { | ||
| if (maxNAryInnerJoin > this.maxNAryInnerJoin) { | ||
| this.maxNAryInnerJoin = maxNAryInnerJoin; | ||
|
|
@@ -816,6 +849,14 @@ public void setPartialLoadDictionary(boolean partialLoadDictionary) { | |
| this.partialLoadDictionary = partialLoadDictionary; | ||
| } | ||
|
|
||
| public Multimap<List<String>, Pair<RelationId, Set<String>>> getTableUsedPartitionNameMap() { | ||
| return tableUsedPartitionNameMap; | ||
| } | ||
|
|
||
| public Map<BaseTableInfo, Collection<Partition>> getMvCanRewritePartitionsMap() { | ||
| return mvCanRewritePartitionsMap; | ||
| } | ||
|
|
||
| public void setPrepareStage(boolean isPrepare) { | ||
| this.prepareStage = isPrepare; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add materializedView.isUseForRewrite