Skip to content

Commit 7d75cfb

Browse files
committed
sql: add tracing logs for generic and custom plan costs
Tracing logs have been added to aid in debugging query planning decisions when `plan_cache_mode` is set to `auto`. Release note: None
1 parent 114eca7 commit 7d75cfb

File tree

2 files changed

+45
-3
lines changed

2 files changed

+45
-3
lines changed

pkg/sql/plan_opt.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -635,16 +635,20 @@ func (opc *optPlanningCtx) buildNonIdealGenericPlan() bool {
635635
// ideal generic query plan is always chosen, if it exists. A non-ideal generic
636636
// plan is chosen if CustomPlanThreshold custom plans have already been built
637637
// and the generic plan is optimal or it has not yet been built.
638-
func (opc *optPlanningCtx) chooseGenericPlan() bool {
638+
func (opc *optPlanningCtx) chooseGenericPlan(ctx context.Context) bool {
639639
ps := opc.p.stmt.Prepared
640640
// Always use an ideal generic plan.
641641
if ps.IdealGenericPlan {
642+
opc.log(ctx, "ideal generic plan")
642643
return true
643644
}
644645
switch opc.p.SessionData().PlanCacheMode {
645646
case sessiondatapb.PlanCacheModeForceGeneric:
646647
return true
647648
case sessiondatapb.PlanCacheModeAuto:
649+
if log.ExpensiveLogEnabled(ctx, 1) {
650+
log.Eventf(ctx, "%s", ps.Costs.Summary())
651+
}
648652
return ps.Costs.NumCustom() >= prep.CustomPlanThreshold &&
649653
(!ps.Costs.HasGeneric() || ps.Costs.IsGenericOptimal())
650654
default:
@@ -706,7 +710,7 @@ func (opc *optPlanningCtx) chooseValidPreparedMemo(ctx context.Context) (*memo.M
706710

707711
// NOTE: The generic or base memos returned below could be nil if they have
708712
// not yet been built.
709-
if opc.chooseGenericPlan() {
713+
if opc.chooseGenericPlan(ctx) {
710714
return prep.GenericMemo, nil
711715
}
712716
return prep.BaseMemo, nil
@@ -775,7 +779,7 @@ func (opc *optPlanningCtx) fetchPreparedMemo(ctx context.Context) (_ *memo.Memo,
775779
prep.Costs.SetGeneric(newMemo.RootExpr().Cost())
776780
// Now that the cost of the generic plan is known, we need to
777781
// re-evaluate the decision to use a generic or custom plan.
778-
if !opc.chooseGenericPlan() {
782+
if !opc.chooseGenericPlan(ctx) {
779783
// The generic plan that we just built is too expensive, so we need
780784
// to build a custom plan. We recursively call fetchPreparedMemo in
781785
// case we have a custom plan that can be reused as a starting point

pkg/sql/prep/statement.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ package prep
77

88
import (
99
"context"
10+
"fmt"
11+
"strings"
1012
"time"
1113

1214
"github.com/cockroachdb/cockroach/pkg/sql/opt/memo"
@@ -213,6 +215,42 @@ func (p *planCosts) avgCustom() memo.Cost {
213215
return memo.Cost{C: sum / float64(p.custom.length)}
214216
}
215217

218+
// Summary returns a single-line string summarizing the custom and generic plan
219+
// costs and full scan counts. The format for custom costs is:
220+
//
221+
// average_custom_cost [num_custom_costs]{custom_cost_0:full_scan_count ...}
222+
//
223+
// The format for generic costs is:
224+
//
225+
// generic_cost:generic_full_scan_count
226+
//
227+
// A full example:
228+
//
229+
// custom costs: 1.23 [3]{1.23:0 1.23:0 1.23:0}, generic cost: 4.56:1
230+
func (p *planCosts) Summary() string {
231+
var sb strings.Builder
232+
sb.WriteString("custom costs: ")
233+
if p.custom.length > 0 {
234+
sb.WriteString(fmt.Sprintf("%.9g [%d]{", p.avgCustom().C, p.custom.length))
235+
for i := 0; i < p.custom.length; i++ {
236+
if i > 0 {
237+
sb.WriteByte(' ')
238+
}
239+
sb.WriteString(fmt.Sprintf("%.9g:%d", p.custom.costs[i].C, p.custom.costs[i].FullScanCount()))
240+
}
241+
sb.WriteByte('}')
242+
} else {
243+
sb.WriteString("none")
244+
}
245+
sb.WriteString(", generic cost: ")
246+
if p.HasGeneric() {
247+
sb.WriteString(fmt.Sprintf("%.9g:%d", p.generic.C, p.generic.FullScanCount()))
248+
} else {
249+
sb.WriteString("none")
250+
}
251+
return sb.String()
252+
}
253+
216254
// Reset clears any previously set costs.
217255
func (p *planCosts) Reset() {
218256
p.generic = memo.Cost{C: 0}

0 commit comments

Comments
 (0)