public override string ExplainOutput(int depth, ExplainOption option) { if (output_.Count != 0) { string r = "Output: " + string.Join(",", output_); output_.ForEach(x => r += x.ExplainExprWithSubqueryExpanded(depth, option)); return(r); } return(null); }
protected string ExplainFilter(Expr filter, int depth, ExplainOption option) { string r = null; if (filter != null) { // append the subquery plan align with filter r = "Filter: " + filter; r += filter.ExplainExprWithSubqueryExpanded(depth, option); } return(r); }
public string Explain(ExplainOption option = null, int depth = 0) { string r = null; bool exp_output = option?.show_output_ ?? true; bool exp_showcost = option?.show_estCost_ ?? false; bool exp_showactual = !(option is null) && option.mode_ >= ExplainMode.analyze; bool exp_id = option?.show_id_ ?? false; if (!(this is PhysicProfiling) && !(this is PhysicCollect)) { r = Utils.Spaces(depth); if (depth == 0) { if (exp_showcost && this is PhysicNode phytop) { var memorycost = ""; var memory = phytop.InclusiveMemory(); if (memory != 0) { memorycost = $", memory={memory}"; } r += $"Total cost: {Math.Truncate(phytop.InclusiveCost() * 100) / 100}{memorycost}\n"; } } else { r += "-> "; } // print line of <nodeName> : <Estimation> <Actual> var id = _ + (clone_.Equals("notclone") ? "" : "_" + clone_); r += $"{this.GetType().Name}{(exp_id ? " " + id : "")} {ExplainInlineDetails()}"; if (this is PhysicNode phynode && phynode.profile_ != null) { if (exp_showcost) { var incCost = Math.Truncate(phynode.InclusiveCost() * 100) / 100; var cost = Math.Truncate(phynode.Cost() * 100) / 100; var memorycost = ""; var memory = phynode.Memory(); if (memory != 0) { memorycost = $", memory={memory}"; } r += $" (inccost={incCost}, cost={cost}, rows={phynode.logic_.Card()}{memorycost})"; } if (exp_showactual) { var profile = phynode.profile_; var loops = profile.nloops_; if (loops == 1 || loops == 0) { Debug.Assert(loops != 0 || profile.nrows_ == 0); r += $" (actual rows={profile.nrows_})"; } else { r += $" (actual rows={profile.nrows_ / loops}, loops={loops})"; } } } r += "\n"; var details = ExplainMoreDetails(depth, option); // print current node's output var output = exp_output ? ExplainOutput(depth, option) : null; if (output != null) { r += Utils.Spaces(depth + 2) + output + "\n"; } if (details != null) { // remove the last \n in case the details is a subquery var trailing = "\n"; if (details[details.Length - 1] == '\n') { trailing = ""; } r += Utils.Spaces(depth + 2) + details + trailing; } depth += 2; } // guard against endless plan: 255 is an arbitrary number. Instead of // throwing here, we choose to print the plan for debugging. // if (depth <= 255) { bool printAsConsumer = false; if (!printAsConsumer) { children_.ForEach(x => r += x.Explain(option, depth)); } } return(r); }
public virtual string ExplainMoreDetails(int depth, ExplainOption option) => null;
// print utilities public virtual string ExplainOutput(int depth, ExplainOption option) => null;
public string Explain(ExplainOption option = null, int depth = 0) { string r = null; bool exp_showcost = option?.show_cost_ ?? false; bool exp_output = option?.show_output_ ?? true; bool exp_id = option?.show_id_ ?? false; if (!(this is PhysicProfiling) && !(this is PhysicCollect)) { r = Utils.Spaces(depth); if (depth == 0) { if (exp_showcost && this is PhysicNode phytop) { r += $"Total cost: {Math.Truncate(phytop.InclusiveCost()*100)/100}\n"; } } else { r += "-> "; } // print line of <nodeName> : <Estimation> <Actual> r += $"{this.GetType().Name}{(exp_id?" "+_:"")} {ExplainInlineDetails()}"; var phynode = this as PhysicNode; if (phynode != null && phynode.profile_ != null) { if (exp_showcost) { var incCost = Math.Truncate(phynode.InclusiveCost() * 100) / 100; var cost = Math.Truncate(phynode.Cost() * 100) / 100; r += $" (inccost={incCost}, cost={cost}, rows={phynode.logic_.Card()})"; } var profile = phynode.profile_; if (profile.nloops_ == 1 || profile.nloops_ == 0) { r += $" (actual rows={profile.nrows_})"; } else { r += $" (actual rows={profile.nrows_ / profile.nloops_}, loops={profile.nloops_})"; } } r += "\n"; var details = ExplainMoreDetails(depth, option); // print current node's output var output = exp_output ? ExplainOutput(depth, option): null; if (output != null) { r += Utils.Spaces(depth + 2) + output + "\n"; } if (details != null) { // remove the last \n in case the details is a subquery var trailing = "\n"; if (details[details.Length - 1] == '\n') { trailing = ""; } r += Utils.Spaces(depth + 2) + details + trailing; } depth += 2; } // guard against endless plan: 255 is an arbitrary number. Instead of // throwing here, we choose to print the plan for debugging. // if (depth <= 255) { bool printAsConsumer = false; if (!printAsConsumer) { children_.ForEach(x => r += x.Explain(option, depth)); } } // details of distributed query emulation if (this is PhysicGather) { int nthreads = QueryOption.num_machines_; int nshuffle = 0; VisitEach(x => { if (x is PhysicRedistribute || x is PhysicBroadcast) { nshuffle++; } }); r += $"\nEmulated {QueryOption.num_machines_} machines distributed run " + $"with {nthreads*(1+nshuffle)} threads\n"; } return(r); }
public override string ExplainMoreDetails(int depth, ExplainOption option) => ExplainFilter(filter_, depth, option);