Skip to content

Commit 842d79b

Browse files
committed
sql: use stmt's span for exec stats propagation
Previously, when sampling the statement, we would always create a new tracing span. However, there is another span that we can use instead: we always create a tracing span for each statement in `connExecutor.execCmd`. That span is not used directly for anything and is needed because the transactions expect that a span is present in their context. This commit utilizes the present tracing span for the sampling purposes which gives us a performance boost (some benchmarks show that this eliminates about a quarter of the performance overhead with "always on" sampling"). Release justification: low-risk update to new functionality. Release note: None
1 parent bc2a1fc commit 842d79b

2 files changed

Lines changed: 37 additions & 16 deletions

File tree

pkg/sql/conn_executor.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,12 +1463,16 @@ func (ex *connExecutor) execCmd(ctx context.Context) error {
14631463
return err // err could be io.EOF
14641464
}
14651465

1466+
// Ensure that every statement has a tracing span set up.
14661467
ctx, sp := tracing.EnsureChildSpan(
14671468
ctx, ex.server.cfg.AmbientCtx.Tracer,
14681469
// We print the type of command, not the String() which includes long
14691470
// statements.
14701471
cmd.command())
14711472
defer sp.Finish()
1473+
// We expect that the span is not used directly, so we'll overwrite the
1474+
// local variable.
1475+
sp = nil
14721476

14731477
if log.ExpensiveLogEnabled(ctx, 2) || ex.eventLog != nil {
14741478
ex.sessionEventf(ctx, "[%s pos:%d] executing %s",

pkg/sql/instrumentation.go

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,11 @@ type instrumentationHelper struct {
9292
finishCollectionDiagnostics func()
9393
withStatementTrace func(trace tracing.Recording, stmt string)
9494

95-
sp *tracing.Span
96-
origCtx context.Context
97-
evalCtx *tree.EvalContext
95+
sp *tracing.Span
96+
// If true, the instrumentation helper is responsible for finishing sp.
97+
finishSpan bool
98+
origCtx context.Context
99+
evalCtx *tree.EvalContext
98100

99101
// If savePlanForStats is true, the explainPlan will be collected and returned
100102
// via PlanForStats().
@@ -164,22 +166,38 @@ func (ih *instrumentationHelper) Setup(
164166

165167
ih.savePlanForStats = appStats.shouldSaveLogicalPlanDescription(fingerprint, implicitTxn)
166168

167-
if sp := tracing.SpanFromContext(ctx); sp != nil && sp.IsVerbose() {
168-
// If verbose tracing was enabled at a higher level, stats collection is
169-
// enabled so that stats are shown in the traces, but no extra work is
170-
// needed by the instrumentationHelper.
171-
ih.collectExecStats = true
172-
return ctx, false
169+
if sp := tracing.SpanFromContext(ctx); sp != nil {
170+
ih.sp = sp
171+
ih.finishSpan = false
172+
if sp.IsVerbose() {
173+
// If verbose tracing was enabled at a higher level, stats
174+
// collection is enabled so that stats are shown in the traces, but
175+
// no extra work is needed by the instrumentationHelper.
176+
ih.collectExecStats = true
177+
return ctx, false
178+
}
179+
} else {
180+
if util.CrdbTestBuild {
181+
panic(errors.AssertionFailedf("the context doesn't have a tracing span"))
182+
}
173183
}
174184

175185
ih.collectExecStats = collectExecStats
176186

177187
if !ih.collectBundle && ih.withStatementTrace == nil && ih.outputMode == unmodifiedOutput {
178188
if ih.collectExecStats {
179-
// If we need to collect stats, create a non-verbose child span. Stats
180-
// will be added as structured metadata and processed in Finish.
181189
ih.origCtx = ctx
190+
if ih.sp != nil {
191+
// The span present in the context is sufficient for us to
192+
// record stats as structured metadata, so there is nothing else
193+
// to do.
194+
return ctx, true
195+
}
196+
// This is an edge case when the span is not present in the original
197+
// context for some reason. This should *never* happen, but we
198+
// choose to be defensive about it.
182199
newCtx, ih.sp = tracing.EnsureChildSpan(ctx, cfg.AmbientCtx.Tracer, "traced statement")
200+
ih.finishSpan = true
183201
return newCtx, true
184202
}
185203
return ctx, false
@@ -190,6 +208,7 @@ func (ih *instrumentationHelper) Setup(
190208
ih.origCtx = ctx
191209
ih.evalCtx = p.EvalContext()
192210
newCtx, ih.sp = tracing.StartVerboseTrace(ctx, cfg.AmbientCtx.Tracer, "traced statement")
211+
ih.finishSpan = true
193212
return newCtx, true
194213
}
195214

@@ -204,15 +223,13 @@ func (ih *instrumentationHelper) Finish(
204223
res RestrictedCommandResult,
205224
retErr error,
206225
) error {
207-
if ih.sp == nil {
208-
return retErr
226+
ctx := ih.origCtx
227+
if ih.finishSpan {
228+
ih.sp.Finish()
209229
}
210230

211231
// Record the statement information that we've collected.
212232
// Note that in case of implicit transactions, the trace contains the auto-commit too.
213-
ih.sp.Finish()
214-
ctx := ih.origCtx
215-
216233
trace := ih.sp.GetRecording()
217234

218235
if ih.withStatementTrace != nil {

0 commit comments

Comments
 (0)