From 57105b830a564a4307750bf79359740588ed5da3 Mon Sep 17 00:00:00 2001 From: lysu Date: Tue, 9 Oct 2018 17:03:51 +0800 Subject: [PATCH 1/7] executor: collect executor time/loop/row count --- ast/misc.go | 5 +- executor/adapter.go | 4 +- executor/admin.go | 19 +++++++ executor/aggregate.go | 14 +++++- executor/analyze.go | 7 +++ executor/builder.go | 31 +++++++++++- executor/checksum.go | 7 +++ executor/ddl.go | 7 +++ executor/delete.go | 8 +++ executor/distsql.go | 14 ++++++ executor/executor.go | 89 +++++++++++++++++++++++++++++++++ executor/explain.go | 8 +++ executor/grant.go | 7 +++ executor/index_lookup_join.go | 7 +++ executor/insert.go | 8 +++ executor/join.go | 13 +++++ executor/load_data.go | 7 +++ executor/load_stats.go | 7 +++ executor/merge_join.go | 8 +++ executor/prepared.go | 20 ++++++++ executor/prepared_test.go | 5 -- executor/projection.go | 8 +++ executor/replace.go | 8 +++ executor/revoke.go | 7 +++ executor/set.go | 6 +++ executor/show.go | 6 +++ executor/simple.go | 7 +++ executor/sort.go | 13 +++++ executor/table_reader.go | 8 +++ executor/trace.go | 6 +++ executor/union_scan.go | 7 +++ executor/update.go | 8 +++ parser/parser.y | 8 +++ planner/core/cbo_test.go | 30 +++++++++++ planner/core/common_plans.go | 22 ++++++-- planner/core/planbuilder.go | 50 ++++++++++-------- sessionctx/stmtctx/stmtctx.go | 1 + util/execdetails/execdetails.go | 54 ++++++++++++++++++++ 38 files changed, 507 insertions(+), 37 deletions(-) diff --git a/ast/misc.go b/ast/misc.go index 02c4dba4d78fe..c4493a24ccd66 100644 --- a/ast/misc.go +++ b/ast/misc.go @@ -118,8 +118,9 @@ func (n *TraceStmt) Accept(v Visitor) (Node, bool) { type ExplainStmt struct { stmtNode - Stmt StmtNode - Format string + Stmt StmtNode + Format string + Analyze bool } // Accept implements Node Accept interface. diff --git a/executor/adapter.go b/executor/adapter.go index 066b210c4afb5..cf9c9702b12a6 100644 --- a/executor/adapter.go +++ b/executor/adapter.go @@ -361,12 +361,12 @@ func (a *ExecStmt) logSlowQuery(txnTS uint64, succ bool) { if sessVars.InRestrictedSQL { internal = "[INTERNAL] " } + execDetail := sessVars.StmtCtx.GetExecDetails() if costTime < threshold { logutil.SlowQueryLogger.Debugf( "[QUERY] %vcost_time:%v %s succ:%v con:%v user:%s txn_start_ts:%v database:%v %v%vsql:%v", - internal, costTime, sessVars.StmtCtx.GetExecDetails(), succ, connID, user, txnTS, currentDB, tableIDs, indexIDs, sql) + internal, costTime, execDetail, succ, connID, user, txnTS, currentDB, tableIDs, indexIDs, sql) } else { - execDetail := sessVars.StmtCtx.GetExecDetails() logutil.SlowQueryLogger.Warnf( "[SLOW_QUERY] %vcost_time:%v %s succ:%v con:%v user:%s txn_start_ts:%v database:%v %v%vsql:%v", internal, costTime, execDetail, succ, connID, user, txnTS, currentDB, tableIDs, indexIDs, sql) diff --git a/executor/admin.go b/executor/admin.go index 1fe645ae15de3..6b4b97a8e5ac0 100644 --- a/executor/admin.go +++ b/executor/admin.go @@ -15,6 +15,7 @@ package executor import ( "math" + "time" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/distsql" @@ -61,6 +62,12 @@ type CheckIndexRangeExec struct { // Next implements the Executor Next interface. func (e *CheckIndexRangeExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() handleIdx := e.schema.Len() - 1 for { @@ -435,6 +442,12 @@ func (e *RecoverIndexExec) backfillIndexInTxn(ctx context.Context, txn kv.Transa // Next implements the Executor Next interface. func (e *RecoverIndexExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if e.done { return nil @@ -571,6 +584,12 @@ func (e *CleanupIndexExec) fetchIndex(ctx context.Context, txn kv.Transaction) e // Next implements the Executor Next interface. func (e *CleanupIndexExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if e.done { return nil diff --git a/executor/aggregate.go b/executor/aggregate.go index d28d5a4c404f7..cc5cf17f5ad2d 100644 --- a/executor/aggregate.go +++ b/executor/aggregate.go @@ -15,6 +15,7 @@ package executor import ( "sync" + "time" "github.com/pingcap/tidb/executor/aggfuncs" "github.com/pingcap/tidb/expression" @@ -501,6 +502,12 @@ func (w *HashAggFinalWorker) run(ctx sessionctx.Context, waitGroup *sync.WaitGro // Next implements the Executor Next interface. func (e *HashAggExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if e.isUnparallelExec { return errors.Trace(e.unparallelExec(ctx, chk)) @@ -756,8 +763,13 @@ func (e *StreamAggExec) Close() error { // Next implements the Executor Next interface. func (e *StreamAggExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() - for !e.executed && chk.NumRows() < e.maxChunkSize { err := e.consumeOneGroup(ctx, chk) if err != nil { diff --git a/executor/analyze.go b/executor/analyze.go index 12e49ff22649d..9e392193a77f5 100644 --- a/executor/analyze.go +++ b/executor/analyze.go @@ -16,6 +16,7 @@ package executor import ( "runtime" "strconv" + "time" "github.com/pingcap/tidb/distsql" "github.com/pingcap/tidb/domain" @@ -52,6 +53,12 @@ const ( // Next implements the Executor Next interface. func (e *AnalyzeExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } concurrency, err := getBuildStatsConcurrency(e.ctx) if err != nil { return errors.Trace(err) diff --git a/executor/builder.go b/executor/builder.go index ae179d9f1b867..aa9c32cc4e6ca 100644 --- a/executor/builder.go +++ b/executor/builder.go @@ -43,6 +43,7 @@ import ( "github.com/pingcap/tidb/types" "github.com/pingcap/tidb/util/admin" "github.com/pingcap/tidb/util/chunk" + "github.com/pingcap/tidb/util/execdetails" "github.com/pingcap/tidb/util/ranger" "github.com/pingcap/tidb/util/timeutil" "github.com/pingcap/tipb/go-tipb" @@ -448,13 +449,12 @@ func (b *executorBuilder) buildLimit(v *plannercore.PhysicalLimit) Executor { func (b *executorBuilder) buildPrepare(v *plannercore.Prepare) Executor { base := newBaseExecutor(b.ctx, v.Schema(), v.ExplainID()) base.initCap = chunk.ZeroCapacity - e := &PrepareExec{ + return &PrepareExec{ baseExecutor: base, is: b.is, name: v.Name, sqlText: v.SQLText, } - return e } func (b *executorBuilder) buildExecute(v *plannercore.Execute) Executor { @@ -659,6 +659,33 @@ func (b *executorBuilder) buildTrace(v *plannercore.Trace) Executor { // buildExplain builds a explain executor. `e.rows` collects final result to `ExplainExec`. func (b *executorBuilder) buildExplain(v *plannercore.Explain) Executor { + if v.Analyze { + stmt := &ExecStmt{ + InfoSchema: GetInfoSchema(b.ctx), + Plan: v.ExecPlan, + StmtNode: v.ExecStmt, + Ctx: b.ctx, + } + b.ctx.GetSessionVars().StmtCtx.ExecStats = execdetails.NewExecutorStats() + ctx := context.Background() + rs, err := stmt.Exec(ctx) + if err != nil { + return nil + } + if rs != nil { + chk := rs.NewChunk() + for { + err := rs.Next(ctx, chk) + if err != nil { + return nil + } + if chk.NumRows() == 0 { + break + } + } + } + } + v.PrepareRows() e := &ExplainExec{ baseExecutor: newBaseExecutor(b.ctx, v.Schema(), v.ExplainID()), } diff --git a/executor/checksum.go b/executor/checksum.go index 04c5d18dc2dcd..08f80ec1de786 100644 --- a/executor/checksum.go +++ b/executor/checksum.go @@ -15,6 +15,7 @@ package executor import ( "strconv" + "time" "github.com/pingcap/tidb/distsql" "github.com/pingcap/tidb/kv" @@ -84,6 +85,12 @@ func (e *ChecksumTableExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *ChecksumTableExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if e.done { return nil diff --git a/executor/ddl.go b/executor/ddl.go index d972c69a7b18e..fc3bc7fc3aad1 100644 --- a/executor/ddl.go +++ b/executor/ddl.go @@ -16,6 +16,7 @@ package executor import ( "fmt" "strings" + "time" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/config" @@ -63,6 +64,12 @@ func (e *DDLExec) toErr(err error) error { // Next implements the Executor Next interface. func (e *DDLExec) Next(ctx context.Context, chk *chunk.Chunk) (err error) { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } if e.done { return nil } diff --git a/executor/delete.go b/executor/delete.go index 026a1975666d8..2043b6a41d05c 100644 --- a/executor/delete.go +++ b/executor/delete.go @@ -14,6 +14,8 @@ package executor import ( + "time" + "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/sessionctx" @@ -43,6 +45,12 @@ type DeleteExec struct { // Next implements the Executor Next interface. func (e *DeleteExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if e.IsMultiTable { return errors.Trace(e.deleteMultiTablesByChunk(ctx)) diff --git a/executor/distsql.go b/executor/distsql.go index d262d8b57bbb0..0beb53c5e95d0 100644 --- a/executor/distsql.go +++ b/executor/distsql.go @@ -19,6 +19,7 @@ import ( "sort" "sync" "sync/atomic" + "time" "unsafe" "github.com/pingcap/tidb/distsql" @@ -243,6 +244,12 @@ func (e *IndexReaderExecutor) Close() error { // Next implements the Executor Next interface. func (e *IndexReaderExecutor) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } err := e.result.Next(ctx, chk) if err != nil { e.feedback.Invalidate() @@ -453,6 +460,7 @@ func (e *IndexLookUpExecutor) startIndexWorker(ctx context.Context, kvRanges []k func (e *IndexLookUpExecutor) startTableWorker(ctx context.Context, workCh <-chan *lookupTableTask) { lookupConcurrencyLimit := e.ctx.GetSessionVars().IndexLookupConcurrency e.tblWorkerWg.Add(lookupConcurrencyLimit) + e.baseExecutor.ctx.GetSessionVars().StmtCtx.ExecStats.GetExecStat(e.id + "_tableReader") for i := 0; i < lookupConcurrencyLimit; i++ { worker := &tableWorker{ workCh: workCh, @@ -512,6 +520,12 @@ func (e *IndexLookUpExecutor) Close() error { // Next implements Exec Next interface. func (e *IndexLookUpExecutor) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() for { resultTask, err := e.getResultTask() diff --git a/executor/executor.go b/executor/executor.go index f57cb97926449..dfbd744dbdac5 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -18,6 +18,7 @@ import ( "runtime" "sync" "sync/atomic" + "time" "github.com/cznic/mathutil" "github.com/pingcap/tidb/ast" @@ -39,12 +40,14 @@ import ( "github.com/pingcap/tidb/util/admin" "github.com/pingcap/tidb/util/chunk" "github.com/pingcap/tidb/util/memory" + "github.com/pingcap/tidb/util/execdetails" "github.com/pkg/errors" log "github.com/sirupsen/logrus" "golang.org/x/net/context" ) var ( + _ Executor = &baseExecutor{} _ Executor = &CheckTableExec{} _ Executor = &HashAggExec{} _ Executor = &LimitExec{} @@ -75,6 +78,7 @@ type baseExecutor struct { maxChunkSize int children []Executor retFieldTypes []*types.FieldType + execStat *execdetails.ExecStat } // Open initializes children recursively and "childrenResults" according to children's schemas. @@ -130,6 +134,7 @@ func newBaseExecutor(ctx sessionctx.Context, schema *expression.Schema, id strin schema: schema, initCap: ctx.GetSessionVars().MaxChunkSize, maxChunkSize: ctx.GetSessionVars().MaxChunkSize, + execStat: ctx.GetSessionVars().StmtCtx.ExecStats.GetExecStat(id), } if schema != nil { cols := schema.Columns @@ -172,6 +177,12 @@ type CancelDDLJobsExec struct { // Next implements the Executor Next interface. func (e *CancelDDLJobsExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.GrowAndReset(e.maxChunkSize) if e.cursor >= len(e.jobIDs) { return nil @@ -201,6 +212,12 @@ type ShowDDLExec struct { // Next implements the Executor Next interface. func (e *ShowDDLExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if e.done { return nil @@ -265,6 +282,12 @@ func (e *ShowDDLJobQueriesExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *ShowDDLJobQueriesExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.GrowAndReset(e.maxChunkSize) if e.cursor >= len(e.jobs) { return nil @@ -308,6 +331,12 @@ func (e *ShowDDLJobsExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *ShowDDLJobsExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.GrowAndReset(e.maxChunkSize) if e.cursor >= len(e.jobs) { return nil @@ -375,6 +404,12 @@ func (e *CheckTableExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *CheckTableExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } if e.done { return nil } @@ -458,6 +493,12 @@ func (e *CheckIndexExec) Close() error { // Next implements the Executor Next interface. func (e *CheckIndexExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } if e.done { return nil } @@ -505,6 +546,12 @@ func (e *ShowSlowExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *ShowSlowExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if e.cursor >= len(e.result) { return nil @@ -570,6 +617,12 @@ func (e *SelectLockExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *SelectLockExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.GrowAndReset(e.maxChunkSize) err := e.children[0].Next(ctx, chk) if err != nil { @@ -614,6 +667,12 @@ type LimitExec struct { // Next implements the Executor Next interface. func (e *LimitExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if e.cursor >= e.end { return nil @@ -733,6 +792,12 @@ func (e *TableDualExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *TableDualExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if e.numReturned >= e.numDualRows { return nil @@ -784,6 +849,12 @@ func (e *SelectionExec) Close() error { // Next implements the Executor Next interface. func (e *SelectionExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.GrowAndReset(e.maxChunkSize) if !e.batched { @@ -859,6 +930,12 @@ type TableScanExec struct { // Next implements the Executor Next interface. func (e *TableScanExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.GrowAndReset(e.maxChunkSize) if e.isVirtualTable { return errors.Trace(e.nextChunk4InfoSchema(ctx, chk)) @@ -959,6 +1036,12 @@ func (e *MaxOneRowExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *MaxOneRowExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if e.evaluated { return nil @@ -1101,6 +1184,12 @@ func (e *UnionExec) resultPuller(ctx context.Context, childID int) { // Next implements the Executor Next interface. func (e *UnionExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.GrowAndReset(e.maxChunkSize) if !e.initialized { e.initialize(ctx) diff --git a/executor/explain.go b/executor/explain.go index afc3f871e0883..0fd156a712eff 100644 --- a/executor/explain.go +++ b/executor/explain.go @@ -14,6 +14,8 @@ package executor import ( + "time" + "github.com/cznic/mathutil" "github.com/pingcap/tidb/util/chunk" "golang.org/x/net/context" @@ -35,6 +37,12 @@ func (e *ExplainExec) Close() error { // Next implements the Executor Next interface. func (e *ExplainExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.GrowAndReset(e.maxChunkSize) if e.cursor >= len(e.rows) { return nil diff --git a/executor/grant.go b/executor/grant.go index 8bff64ddba034..2b7cddc07574d 100644 --- a/executor/grant.go +++ b/executor/grant.go @@ -16,6 +16,7 @@ package executor import ( "fmt" "strings" + "time" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/domain" @@ -54,6 +55,12 @@ type GrantExec struct { // Next implements the Executor Next interface. func (e *GrantExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } if e.done { return nil } diff --git a/executor/index_lookup_join.go b/executor/index_lookup_join.go index a0bc75994bc92..34a27e32c94e3 100644 --- a/executor/index_lookup_join.go +++ b/executor/index_lookup_join.go @@ -18,6 +18,7 @@ import ( "runtime" "sort" "sync" + "time" "unsafe" "github.com/pingcap/tidb/expression" @@ -189,6 +190,12 @@ func (e *IndexLookUpJoin) newInnerWorker(taskCh chan *lookUpJoinTask) *innerWork // Next implements the Executor interface. func (e *IndexLookUpJoin) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() e.joinResult.Reset() for { diff --git a/executor/insert.go b/executor/insert.go index 932a2c09ce326..980d90f154cb2 100644 --- a/executor/insert.go +++ b/executor/insert.go @@ -14,6 +14,8 @@ package executor import ( + "time" + "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/mysql" @@ -128,6 +130,12 @@ func (e *InsertExec) batchUpdateDupRows(newRows [][]types.Datum) error { // Next implements Exec Next interface. func (e *InsertExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() cols, err := e.getColumns(e.Table.Cols()) if err != nil { diff --git a/executor/join.go b/executor/join.go index 585dc60348d42..37366efb7d660 100644 --- a/executor/join.go +++ b/executor/join.go @@ -17,6 +17,7 @@ import ( "math" "sync" "sync/atomic" + "time" "unsafe" "github.com/pingcap/tidb/expression" @@ -508,6 +509,12 @@ func (e *HashJoinExec) join2Chunk(workerID uint, outerChk *chunk.Chunk, joinResu // step 1. fetch data from inner child and build a hash table; // step 2. fetch data from outer child in a background goroutine and probe the hash table in multiple join workers. func (e *HashJoinExec) Next(ctx context.Context, chk *chunk.Chunk) (err error) { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } if !e.prepared { e.innerFinished = make(chan error, 1) go util.WithRecovery(func() { e.fetchInnerAndBuildHashTable(ctx) }, e.finishFetchInnerAndBuildHashTable) @@ -721,6 +728,12 @@ func (e *NestedLoopApplyExec) fetchAllInners(ctx context.Context) error { // Next implements the Executor interface. func (e *NestedLoopApplyExec) Next(ctx context.Context, chk *chunk.Chunk) (err error) { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() for { if e.innerIter == nil || e.innerIter.Current() == e.innerIter.End() { diff --git a/executor/load_data.go b/executor/load_data.go index d6ee3724a3a74..08007f8c33727 100644 --- a/executor/load_data.go +++ b/executor/load_data.go @@ -17,6 +17,7 @@ import ( "bytes" "fmt" "strings" + "time" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/sessionctx" @@ -50,6 +51,12 @@ func NewLoadDataInfo(ctx sessionctx.Context, row []types.Datum, tbl table.Table, // Next implements the Executor Next interface. func (e *LoadDataExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.GrowAndReset(e.maxChunkSize) // TODO: support load data without local field. if !e.IsLocal { diff --git a/executor/load_stats.go b/executor/load_stats.go index 968d3b10e0601..2e5058ffe6203 100644 --- a/executor/load_stats.go +++ b/executor/load_stats.go @@ -15,6 +15,7 @@ package executor import ( "encoding/json" + "time" "github.com/pingcap/tidb/domain" "github.com/pingcap/tidb/sessionctx" @@ -51,6 +52,12 @@ const LoadStatsVarKey loadStatsVarKeyType = 0 // Next implements the Executor Next interface. func (e *LoadStatsExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.GrowAndReset(e.maxChunkSize) if len(e.info.Path) == 0 { return errors.New("Load Stats: file path is empty") diff --git a/executor/merge_join.go b/executor/merge_join.go index 56f2102e763e2..f2f05214c60fc 100644 --- a/executor/merge_join.go +++ b/executor/merge_join.go @@ -14,6 +14,8 @@ package executor import ( + "time" + "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/sessionctx/stmtctx" "github.com/pingcap/tidb/util/chunk" @@ -261,6 +263,12 @@ func (e *MergeJoinExec) prepare(ctx context.Context, chk *chunk.Chunk) error { // Next implements the Executor Next interface. func (e *MergeJoinExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if !e.prepared { if err := e.prepare(ctx, chk); err != nil { diff --git a/executor/prepared.go b/executor/prepared.go index a006bf0d6edd3..f2f1866e7cab2 100644 --- a/executor/prepared.go +++ b/executor/prepared.go @@ -16,6 +16,8 @@ package executor import ( "math" "sort" + "sync/atomic" + "time" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/expression" @@ -95,6 +97,12 @@ func NewPrepareExec(ctx sessionctx.Context, is infoschema.InfoSchema, sqlTxt str // Next implements the Executor Next interface. func (e *PrepareExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } vars := e.ctx.GetSessionVars() if e.ID != 0 { // Must be the case when we retry a prepare. @@ -193,6 +201,12 @@ type ExecuteExec struct { // Next implements the Executor Next interface. func (e *ExecuteExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } return nil } @@ -228,6 +242,12 @@ type DeallocateExec struct { // Next implements the Executor Next interface. func (e *DeallocateExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } vars := e.ctx.GetSessionVars() id, ok := vars.PreparedStmtNameToID[e.Name] if !ok { diff --git a/executor/prepared_test.go b/executor/prepared_test.go index 3e19ca79b9e95..1e804c2a24799 100644 --- a/executor/prepared_test.go +++ b/executor/prepared_test.go @@ -178,11 +178,6 @@ func (s *testSuite) TestPrepared(c *C) { _, _, fields, err = tk.Se.PrepareStmt("update prepare3 set a = ?") c.Assert(err, IsNil) c.Assert(len(fields), Equals, 0) - - // Coverage. - exec := &executor.ExecuteExec{} - exec.Next(ctx, nil) - exec.Close() } } diff --git a/executor/projection.go b/executor/projection.go index 168ce32f39914..d12d7f9e9fb55 100644 --- a/executor/projection.go +++ b/executor/projection.go @@ -14,6 +14,8 @@ package executor import ( + "time" + "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/sessionctx" "github.com/pingcap/tidb/util/chunk" @@ -139,6 +141,12 @@ func (e *ProjectionExec) Open(ctx context.Context) error { // +------------------------------+ +----------------------+ // func (e *ProjectionExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.GrowAndReset(e.maxChunkSize) if e.isUnparallelExec() { return errors.Trace(e.unParallelExecute(ctx, chk)) diff --git a/executor/replace.go b/executor/replace.go index dbe79cfde4817..4367a39dc8d53 100644 --- a/executor/replace.go +++ b/executor/replace.go @@ -14,6 +14,8 @@ package executor import ( + "time" + "github.com/pingcap/tidb/table/tables" "github.com/pingcap/tidb/tablecodec" "github.com/pingcap/tidb/types" @@ -177,6 +179,12 @@ func (e *ReplaceExec) exec(newRows [][]types.Datum) error { // Next implements the Executor Next interface. func (e *ReplaceExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() cols, err := e.getColumns(e.Table.Cols()) if err != nil { diff --git a/executor/revoke.go b/executor/revoke.go index 3f2edb6c7249b..fb9adb15881be 100644 --- a/executor/revoke.go +++ b/executor/revoke.go @@ -15,6 +15,7 @@ package executor import ( "fmt" + "time" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/domain" @@ -52,6 +53,12 @@ type RevokeExec struct { // Next implements the Executor Next interface. func (e *RevokeExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } if e.done { return nil } diff --git a/executor/set.go b/executor/set.go index 76562a6a4f8f9..8e948bebe7049 100644 --- a/executor/set.go +++ b/executor/set.go @@ -43,6 +43,12 @@ type SetExecutor struct { // Next implements the Executor Next interface. func (e *SetExecutor) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if e.done { return nil diff --git a/executor/show.go b/executor/show.go index 0a76e27f683f7..1960bde14cba7 100644 --- a/executor/show.go +++ b/executor/show.go @@ -64,6 +64,12 @@ type ShowExec struct { // Next implements the Executor Next interface. func (e *ShowExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.GrowAndReset(e.maxChunkSize) if e.result == nil { e.result = e.newFirstChunk() diff --git a/executor/simple.go b/executor/simple.go index e05f20012260d..5499e803dd6f8 100644 --- a/executor/simple.go +++ b/executor/simple.go @@ -16,6 +16,7 @@ package executor import ( "fmt" "strings" + "time" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/config" @@ -49,6 +50,12 @@ type SimpleExec struct { // Next implements the Executor Next interface. func (e *SimpleExec) Next(ctx context.Context, chk *chunk.Chunk) (err error) { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } if e.done { return nil } diff --git a/executor/sort.go b/executor/sort.go index 95b9ecac29d38..aa3ff46e7f8ad 100644 --- a/executor/sort.go +++ b/executor/sort.go @@ -16,6 +16,7 @@ package executor import ( "container/heap" "sort" + "time" "github.com/pingcap/tidb/expression" plannercore "github.com/pingcap/tidb/planner/core" @@ -73,6 +74,12 @@ func (e *SortExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *SortExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if !e.fetched { err := e.fetchRowChunks(ctx) @@ -296,6 +303,12 @@ func (e *TopNExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *TopNExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if !e.fetched { e.totalLimit = int(e.limit.Offset + e.limit.Count) diff --git a/executor/table_reader.go b/executor/table_reader.go index ea9de3ed2b6f9..d9053460107de 100644 --- a/executor/table_reader.go +++ b/executor/table_reader.go @@ -14,6 +14,8 @@ package executor import ( + "time" + "github.com/pingcap/tidb/distsql" "github.com/pingcap/tidb/model" plannercore "github.com/pingcap/tidb/planner/core" @@ -98,6 +100,12 @@ func (e *TableReaderExecutor) Open(ctx context.Context) error { // Next fills data into the chunk passed by its caller. // The task was actually done by tableReaderHandler. func (e *TableReaderExecutor) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } if err := e.resultHandler.nextChunk(ctx, chk); err != nil { e.feedback.Invalidate() return err diff --git a/executor/trace.go b/executor/trace.go index fd6db06e6346d..872109ab9837a 100644 --- a/executor/trace.go +++ b/executor/trace.go @@ -45,6 +45,12 @@ type TraceExec struct { // Next executes real query and collects span later. func (e *TraceExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if e.exhausted { return nil diff --git a/executor/union_scan.go b/executor/union_scan.go index 3c1682936d71d..a64e1c7991439 100644 --- a/executor/union_scan.go +++ b/executor/union_scan.go @@ -15,6 +15,7 @@ package executor import ( "sort" + "time" "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/model" @@ -125,6 +126,12 @@ func (us *UnionScanExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (us *UnionScanExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if us.execStat != nil { + start := time.Now() + defer func() { + us.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.GrowAndReset(us.maxChunkSize) mutableRow := chunk.MutRowFromTypes(us.retTypes()) for i, batchSize := 0, chk.Capacity(); i < batchSize; i++ { diff --git a/executor/update.go b/executor/update.go index de60b92ab8a01..72865918b5e6a 100644 --- a/executor/update.go +++ b/executor/update.go @@ -14,6 +14,8 @@ package executor import ( + "time" + "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/model" @@ -112,6 +114,12 @@ func (e *UpdateExec) canNotUpdate(handle types.Datum) bool { // Next implements the Executor Next interface. func (e *UpdateExec) Next(ctx context.Context, chk *chunk.Chunk) error { + if e.execStat != nil { + start := time.Now() + defer func() { + e.execStat.Record(time.Now().Sub(start), chk.NumRows()) + }() + } chk.Reset() if !e.fetched { err := e.fetchChunkRows(ctx) diff --git a/parser/parser.y b/parser/parser.y index 8ad6702901a70..1cc4fbbc71048 100644 --- a/parser/parser.y +++ b/parser/parser.y @@ -2312,6 +2312,14 @@ ExplainStmt: Format: $4, } } +| ExplainSym "ANALYZE" ExplainableStmt + { + $$ = &ast.ExplainStmt { + Stmt: $3, + Format: "row", + Analyze: true, + } + } LengthNum: NUM diff --git a/planner/core/cbo_test.go b/planner/core/cbo_test.go index 70bd9b686c7d1..e8621d754e79f 100644 --- a/planner/core/cbo_test.go +++ b/planner/core/cbo_test.go @@ -15,6 +15,7 @@ package core_test import ( "fmt" + "strings" "testing" . "github.com/pingcap/check" @@ -37,6 +38,35 @@ var _ = Suite(&testAnalyzeSuite{}) type testAnalyzeSuite struct { } +func (s *testAnalyzeSuite) TestExplainAnalyze(c *C) { + defer testleak.AfterTest(c)() + store, dom, err := newStoreWithBootstrap() + c.Assert(err, IsNil) + tk := testkit.NewTestKit(c, store) + defer func() { + dom.Close() + store.Close() + }() + tk.MustExec("use test") + tk.MustExec("create table t1(a int, b int, c int, key idx(a, b))") + tk.MustExec("create table t2(a int, b int)") + tk.MustExec("insert into t1 values (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4)") + tk.MustExec("insert into t2 values (2, 22), (3, 33), (5, 55)") + tk.MustExec("analyze table t1, t2") + rs := tk.MustQuery("explain analyze select t1.a, t1.b, sum(t1.c) from t1 join t2 on t1.a = t2.b where t1.a > 1") + c.Assert(len(rs.Rows()), Equals, 10) + for _, row := range rs.Rows() { + c.Assert(len(row), Equals, 5) + taskType := row[2].(string) + if taskType != "cop" { + execInfo := row[4].(string) + c.Assert(strings.Contains(execInfo, "time"), Equals, true) + c.Assert(strings.Contains(execInfo, "loops"), Equals, true) + c.Assert(strings.Contains(execInfo, "rows"), Equals, true) + } + } +} + // TestCBOWithoutAnalyze tests the plan with stats that only have count info. func (s *testAnalyzeSuite) TestCBOWithoutAnalyze(c *C) { defer testleak.AfterTest(c)() diff --git a/planner/core/common_plans.go b/planner/core/common_plans.go index 82a60716c13be..be81862b7979b 100644 --- a/planner/core/common_plans.go +++ b/planner/core/common_plans.go @@ -410,11 +410,15 @@ type Explain struct { StmtPlan Plan Rows [][]string explainedPlans map[int]bool + PrepareRows func() error + Analyze bool + ExecStmt ast.StmtNode + ExecPlan Plan } // explainPlanInRowFormat generates explain information for root-tasks. -func (e *Explain) explainPlanInRowFormat(p PhysicalPlan, TaskType, indent string, isLastChild bool) { - e.prepareOperatorInfo(p, TaskType, indent, isLastChild) +func (e *Explain) explainPlanInRowFormat(p PhysicalPlan, taskType, indent string, isLastChild bool) { + e.prepareOperatorInfo(p, taskType, indent, isLastChild) e.explainedPlans[p.ID()] = true // For every child we create a new sub-tree rooted by it. @@ -423,7 +427,7 @@ func (e *Explain) explainPlanInRowFormat(p PhysicalPlan, TaskType, indent string if e.explainedPlans[child.ID()] { continue } - e.explainPlanInRowFormat(child.(PhysicalPlan), TaskType, childIndent, i == len(p.Children())-1) + e.explainPlanInRowFormat(child.(PhysicalPlan), taskType, childIndent, i == len(p.Children())-1) } switch copPlan := p.(type) { @@ -439,10 +443,18 @@ func (e *Explain) explainPlanInRowFormat(p PhysicalPlan, TaskType, indent string // prepareOperatorInfo generates the following information for every plan: // operator id, task type, operator info, and the estemated row count. -func (e *Explain) prepareOperatorInfo(p PhysicalPlan, TaskType string, indent string, isLastChild bool) { +func (e *Explain) prepareOperatorInfo(p PhysicalPlan, taskType string, indent string, isLastChild bool) { operatorInfo := p.ExplainInfo() count := string(strconv.AppendFloat([]byte{}, p.statsInfo().RowCount, 'f', 2, 64)) - row := []string{e.prettyIdentifier(p.ExplainID(), indent, isLastChild), count, TaskType, operatorInfo} + row := []string{e.prettyIdentifier(p.ExplainID(), indent, isLastChild), count, taskType, operatorInfo} + if e.Analyze { + execStat := e.ctx.GetSessionVars().StmtCtx.ExecStats + if taskType == "cop" { + row = append(row, "") //TODO: wait collect resp from tikv + } else { + row = append(row, execStat.GetExecStat(p.ExplainID()).String()) + } + } e.Rows = append(e.Rows, row) } diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 4bc1d6bd25208..ef9b458c1697c 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -1465,27 +1465,37 @@ func (b *PlanBuilder) buildExplain(explain *ast.ExplainStmt) (Plan, error) { return nil, ErrUnsupportedType.GenWithStackByArgs(targetPlan) } } - p := &Explain{StmtPlan: pp} - switch strings.ToLower(explain.Format) { - case ast.ExplainFormatROW: - retFields := []string{"id", "count", "task", "operator info"} - schema := expression.NewSchema(make([]*expression.Column, 0, len(retFields))...) - for _, fieldName := range retFields { - schema.Append(buildColumn("", fieldName, mysql.TypeString, mysql.MaxBlobWidth)) - } - p.SetSchema(schema) - p.explainedPlans = map[int]bool{} - p.explainPlanInRowFormat(p.StmtPlan.(PhysicalPlan), "root", "", true) - case ast.ExplainFormatDOT: - retFields := []string{"dot contents"} - schema := expression.NewSchema(make([]*expression.Column, 0, len(retFields))...) - for _, fieldName := range retFields { - schema.Append(buildColumn("", fieldName, mysql.TypeString, mysql.MaxBlobWidth)) + p := &Explain{StmtPlan: pp, Analyze: explain.Analyze, ExecStmt: explain.Stmt, ExecPlan: targetPlan} + p.ctx = b.ctx + p.PrepareRows = func() error { + switch strings.ToLower(explain.Format) { + case ast.ExplainFormatROW: + retFields := []string{"id", "count", "task", "operator info"} + if explain.Analyze { + retFields = append(retFields, "execution_info") + } + schema := expression.NewSchema(make([]*expression.Column, 0, len(retFields))...) + for _, fieldName := range retFields { + schema.Append(buildColumn("", fieldName, mysql.TypeString, mysql.MaxBlobWidth)) + } + p.SetSchema(schema) + p.explainedPlans = map[int]bool{} + p.explainPlanInRowFormat(p.StmtPlan.(PhysicalPlan), "root", "", true) + if explain.Analyze { + b.ctx.GetSessionVars().StmtCtx.ExecStats = nil + } + case ast.ExplainFormatDOT: + retFields := []string{"dot contents"} + schema := expression.NewSchema(make([]*expression.Column, 0, len(retFields))...) + for _, fieldName := range retFields { + schema.Append(buildColumn("", fieldName, mysql.TypeString, mysql.MaxBlobWidth)) + } + p.SetSchema(schema) + p.prepareDotInfo(p.StmtPlan.(PhysicalPlan)) + default: + return errors.Errorf("explain format '%s' is not supported now", explain.Format) } - p.SetSchema(schema) - p.prepareDotInfo(p.StmtPlan.(PhysicalPlan)) - default: - return nil, errors.Errorf("explain format '%s' is not supported now", explain.Format) + return nil } return p, nil } diff --git a/sessionctx/stmtctx/stmtctx.go b/sessionctx/stmtctx/stmtctx.go index 2fc9adfd49712..c2456ab4bff7c 100644 --- a/sessionctx/stmtctx/stmtctx.go +++ b/sessionctx/stmtctx/stmtctx.go @@ -77,6 +77,7 @@ type StatementContext struct { Priority mysql.PriorityEnum NotFillCache bool MemTracker *memory.Tracker + ExecStats execdetails.ExecStats TableIDs []int64 IndexIDs []int64 } diff --git a/util/execdetails/execdetails.go b/util/execdetails/execdetails.go index a73c5b2cd60b5..10afd3db4cc37 100644 --- a/util/execdetails/execdetails.go +++ b/util/execdetails/execdetails.go @@ -14,8 +14,10 @@ package execdetails import ( + "bytes" "fmt" "strings" + "sync/atomic" "time" ) @@ -52,3 +54,55 @@ func (d ExecDetails) String() string { } return strings.Join(parts, " ") } + +// ExecStats collects executors's execution info. +type ExecStats map[string]*ExecStat + +// ExecStat collects one executor's execution info. +type ExecStat struct { + loop int32 + consume int64 + rows int64 +} + +// NewExecutorStats creates new executor collector. +func NewExecutorStats() ExecStats { + return ExecStats(make(map[string]*ExecStat)) +} + +// GetExecStat gets execStat for a executor. +func (e ExecStats) GetExecStat(planID string) *ExecStat { + if e == nil { + return nil + } + execStat, exists := e[planID] + if !exists { + execStat = &ExecStat{} + e[planID] = execStat + } + return execStat +} + +func (e ExecStats) String() string { + var buff bytes.Buffer + buff.WriteString("(") + for planID, stat := range e { + buff.WriteString(planID + ":" + stat.String() + ",") + } + buff.WriteString(")") + return buff.String() +} + +// Record records executor's execution. +func (e *ExecStat) Record(d time.Duration, rowNum int) { + atomic.AddInt32(&e.loop, 1) + atomic.AddInt64(&e.consume, int64(d)) + atomic.AddInt64(&e.rows, int64(rowNum)) +} + +func (e *ExecStat) String() string { + if e == nil { + return "" + } + return fmt.Sprintf("time:%f, loops:%d, rows:%d", time.Duration(e.consume).Seconds()*1e3, e.loop, e.rows) +} From 28db228e1c7e51cb5a81bb9b168e403dc1b19b80 Mon Sep 17 00:00:00 2001 From: lysu Date: Tue, 9 Oct 2018 17:12:54 +0800 Subject: [PATCH 2/7] executor: fix rebase question --- executor/executor.go | 2 +- executor/prepared.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/executor/executor.go b/executor/executor.go index dfbd744dbdac5..402d44f7827e5 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -39,8 +39,8 @@ import ( "github.com/pingcap/tidb/types" "github.com/pingcap/tidb/util/admin" "github.com/pingcap/tidb/util/chunk" - "github.com/pingcap/tidb/util/memory" "github.com/pingcap/tidb/util/execdetails" + "github.com/pingcap/tidb/util/memory" "github.com/pkg/errors" log "github.com/sirupsen/logrus" "golang.org/x/net/context" diff --git a/executor/prepared.go b/executor/prepared.go index f2f1866e7cab2..c5939c83f01a7 100644 --- a/executor/prepared.go +++ b/executor/prepared.go @@ -16,7 +16,6 @@ package executor import ( "math" "sort" - "sync/atomic" "time" "github.com/pingcap/tidb/ast" From 30e0278eef6ef79fed4b60a470d0345690d18f7e Mon Sep 17 00:00:00 2001 From: lysu Date: Thu, 11 Oct 2018 20:21:23 +0800 Subject: [PATCH 3/7] address comment - rename - remove unuse code --- executor/admin.go | 19 ------- executor/aggregate.go | 12 ++--- executor/analyze.go | 7 --- executor/builder.go | 2 +- executor/checksum.go | 7 --- executor/ddl.go | 7 --- executor/delete.go | 8 --- executor/distsql.go | 14 ++---- executor/executor.go | 88 ++++++--------------------------- executor/explain.go | 8 --- executor/grant.go | 7 --- executor/index_lookup_join.go | 6 +-- executor/insert.go | 8 --- executor/join.go | 12 ++--- executor/load_data.go | 7 --- executor/load_stats.go | 8 --- executor/merge_join.go | 6 +-- executor/prepared.go | 19 ------- executor/projection.go | 6 +-- executor/replace.go | 8 --- executor/revoke.go | 8 --- executor/set.go | 6 --- executor/show.go | 6 --- executor/simple.go | 7 --- executor/sort.go | 12 ++--- executor/table_reader.go | 6 +-- executor/trace.go | 6 --- executor/union_scan.go | 6 +-- executor/update.go | 8 --- planner/core/common_plans.go | 4 +- planner/core/planbuilder.go | 2 +- sessionctx/stmtctx/stmtctx.go | 2 +- util/execdetails/execdetails.go | 33 +++++++------ 33 files changed, 66 insertions(+), 299 deletions(-) diff --git a/executor/admin.go b/executor/admin.go index 6b4b97a8e5ac0..1fe645ae15de3 100644 --- a/executor/admin.go +++ b/executor/admin.go @@ -15,7 +15,6 @@ package executor import ( "math" - "time" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/distsql" @@ -62,12 +61,6 @@ type CheckIndexRangeExec struct { // Next implements the Executor Next interface. func (e *CheckIndexRangeExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.Reset() handleIdx := e.schema.Len() - 1 for { @@ -442,12 +435,6 @@ func (e *RecoverIndexExec) backfillIndexInTxn(ctx context.Context, txn kv.Transa // Next implements the Executor Next interface. func (e *RecoverIndexExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.Reset() if e.done { return nil @@ -584,12 +571,6 @@ func (e *CleanupIndexExec) fetchIndex(ctx context.Context, txn kv.Transaction) e // Next implements the Executor Next interface. func (e *CleanupIndexExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.Reset() if e.done { return nil diff --git a/executor/aggregate.go b/executor/aggregate.go index cc5cf17f5ad2d..1959e298dd77d 100644 --- a/executor/aggregate.go +++ b/executor/aggregate.go @@ -502,11 +502,9 @@ func (w *HashAggFinalWorker) run(ctx sessionctx.Context, waitGroup *sync.WaitGro // Next implements the Executor Next interface. func (e *HashAggExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.Reset() if e.isUnparallelExec { @@ -763,11 +761,9 @@ func (e *StreamAggExec) Close() error { // Next implements the Executor Next interface. func (e *StreamAggExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.Reset() for !e.executed && chk.NumRows() < e.maxChunkSize { diff --git a/executor/analyze.go b/executor/analyze.go index 9e392193a77f5..12e49ff22649d 100644 --- a/executor/analyze.go +++ b/executor/analyze.go @@ -16,7 +16,6 @@ package executor import ( "runtime" "strconv" - "time" "github.com/pingcap/tidb/distsql" "github.com/pingcap/tidb/domain" @@ -53,12 +52,6 @@ const ( // Next implements the Executor Next interface. func (e *AnalyzeExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } concurrency, err := getBuildStatsConcurrency(e.ctx) if err != nil { return errors.Trace(err) diff --git a/executor/builder.go b/executor/builder.go index aa9c32cc4e6ca..51aaeee9f3537 100644 --- a/executor/builder.go +++ b/executor/builder.go @@ -666,7 +666,7 @@ func (b *executorBuilder) buildExplain(v *plannercore.Explain) Executor { StmtNode: v.ExecStmt, Ctx: b.ctx, } - b.ctx.GetSessionVars().StmtCtx.ExecStats = execdetails.NewExecutorStats() + b.ctx.GetSessionVars().StmtCtx.RuntimeStats = execdetails.NewRuntimeStats() ctx := context.Background() rs, err := stmt.Exec(ctx) if err != nil { diff --git a/executor/checksum.go b/executor/checksum.go index 08f80ec1de786..04c5d18dc2dcd 100644 --- a/executor/checksum.go +++ b/executor/checksum.go @@ -15,7 +15,6 @@ package executor import ( "strconv" - "time" "github.com/pingcap/tidb/distsql" "github.com/pingcap/tidb/kv" @@ -85,12 +84,6 @@ func (e *ChecksumTableExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *ChecksumTableExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.Reset() if e.done { return nil diff --git a/executor/ddl.go b/executor/ddl.go index fc3bc7fc3aad1..d972c69a7b18e 100644 --- a/executor/ddl.go +++ b/executor/ddl.go @@ -16,7 +16,6 @@ package executor import ( "fmt" "strings" - "time" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/config" @@ -64,12 +63,6 @@ func (e *DDLExec) toErr(err error) error { // Next implements the Executor Next interface. func (e *DDLExec) Next(ctx context.Context, chk *chunk.Chunk) (err error) { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } if e.done { return nil } diff --git a/executor/delete.go b/executor/delete.go index 2043b6a41d05c..026a1975666d8 100644 --- a/executor/delete.go +++ b/executor/delete.go @@ -14,8 +14,6 @@ package executor import ( - "time" - "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/sessionctx" @@ -45,12 +43,6 @@ type DeleteExec struct { // Next implements the Executor Next interface. func (e *DeleteExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.Reset() if e.IsMultiTable { return errors.Trace(e.deleteMultiTablesByChunk(ctx)) diff --git a/executor/distsql.go b/executor/distsql.go index 0beb53c5e95d0..6c4f40efc3769 100644 --- a/executor/distsql.go +++ b/executor/distsql.go @@ -244,11 +244,9 @@ func (e *IndexReaderExecutor) Close() error { // Next implements the Executor Next interface. func (e *IndexReaderExecutor) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } err := e.result.Next(ctx, chk) if err != nil { @@ -460,7 +458,7 @@ func (e *IndexLookUpExecutor) startIndexWorker(ctx context.Context, kvRanges []k func (e *IndexLookUpExecutor) startTableWorker(ctx context.Context, workCh <-chan *lookupTableTask) { lookupConcurrencyLimit := e.ctx.GetSessionVars().IndexLookupConcurrency e.tblWorkerWg.Add(lookupConcurrencyLimit) - e.baseExecutor.ctx.GetSessionVars().StmtCtx.ExecStats.GetExecStat(e.id + "_tableReader") + e.baseExecutor.ctx.GetSessionVars().StmtCtx.RuntimeStats.GetRuntimeStat(e.id + "_tableReader") for i := 0; i < lookupConcurrencyLimit; i++ { worker := &tableWorker{ workCh: workCh, @@ -520,11 +518,9 @@ func (e *IndexLookUpExecutor) Close() error { // Next implements Exec Next interface. func (e *IndexLookUpExecutor) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.Reset() for { diff --git a/executor/executor.go b/executor/executor.go index 402d44f7827e5..2a00464f011a8 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -78,7 +78,7 @@ type baseExecutor struct { maxChunkSize int children []Executor retFieldTypes []*types.FieldType - execStat *execdetails.ExecStat + runtimeStat *execdetails.RuntimeStat } // Open initializes children recursively and "childrenResults" according to children's schemas. @@ -134,7 +134,7 @@ func newBaseExecutor(ctx sessionctx.Context, schema *expression.Schema, id strin schema: schema, initCap: ctx.GetSessionVars().MaxChunkSize, maxChunkSize: ctx.GetSessionVars().MaxChunkSize, - execStat: ctx.GetSessionVars().StmtCtx.ExecStats.GetExecStat(id), + runtimeStat: ctx.GetSessionVars().StmtCtx.RuntimeStats.GetRuntimeStat(id), } if schema != nil { cols := schema.Columns @@ -177,11 +177,9 @@ type CancelDDLJobsExec struct { // Next implements the Executor Next interface. func (e *CancelDDLJobsExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.GrowAndReset(e.maxChunkSize) if e.cursor >= len(e.jobIDs) { @@ -212,12 +210,6 @@ type ShowDDLExec struct { // Next implements the Executor Next interface. func (e *ShowDDLExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.Reset() if e.done { return nil @@ -282,12 +274,6 @@ func (e *ShowDDLJobQueriesExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *ShowDDLJobQueriesExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.GrowAndReset(e.maxChunkSize) if e.cursor >= len(e.jobs) { return nil @@ -331,12 +317,6 @@ func (e *ShowDDLJobsExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *ShowDDLJobsExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.GrowAndReset(e.maxChunkSize) if e.cursor >= len(e.jobs) { return nil @@ -404,12 +384,6 @@ func (e *CheckTableExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *CheckTableExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } if e.done { return nil } @@ -493,12 +467,6 @@ func (e *CheckIndexExec) Close() error { // Next implements the Executor Next interface. func (e *CheckIndexExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } if e.done { return nil } @@ -546,12 +514,6 @@ func (e *ShowSlowExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *ShowSlowExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.Reset() if e.cursor >= len(e.result) { return nil @@ -617,12 +579,6 @@ func (e *SelectLockExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *SelectLockExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.GrowAndReset(e.maxChunkSize) err := e.children[0].Next(ctx, chk) if err != nil { @@ -667,11 +623,9 @@ type LimitExec struct { // Next implements the Executor Next interface. func (e *LimitExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.Reset() if e.cursor >= e.end { @@ -792,11 +746,9 @@ func (e *TableDualExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *TableDualExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.Reset() if e.numReturned >= e.numDualRows { @@ -849,11 +801,9 @@ func (e *SelectionExec) Close() error { // Next implements the Executor Next interface. func (e *SelectionExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.GrowAndReset(e.maxChunkSize) @@ -930,11 +880,9 @@ type TableScanExec struct { // Next implements the Executor Next interface. func (e *TableScanExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.GrowAndReset(e.maxChunkSize) if e.isVirtualTable { @@ -1036,11 +984,9 @@ func (e *MaxOneRowExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *MaxOneRowExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.Reset() if e.evaluated { @@ -1184,11 +1130,9 @@ func (e *UnionExec) resultPuller(ctx context.Context, childID int) { // Next implements the Executor Next interface. func (e *UnionExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.GrowAndReset(e.maxChunkSize) if !e.initialized { diff --git a/executor/explain.go b/executor/explain.go index 0fd156a712eff..afc3f871e0883 100644 --- a/executor/explain.go +++ b/executor/explain.go @@ -14,8 +14,6 @@ package executor import ( - "time" - "github.com/cznic/mathutil" "github.com/pingcap/tidb/util/chunk" "golang.org/x/net/context" @@ -37,12 +35,6 @@ func (e *ExplainExec) Close() error { // Next implements the Executor Next interface. func (e *ExplainExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.GrowAndReset(e.maxChunkSize) if e.cursor >= len(e.rows) { return nil diff --git a/executor/grant.go b/executor/grant.go index 2b7cddc07574d..8bff64ddba034 100644 --- a/executor/grant.go +++ b/executor/grant.go @@ -16,7 +16,6 @@ package executor import ( "fmt" "strings" - "time" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/domain" @@ -55,12 +54,6 @@ type GrantExec struct { // Next implements the Executor Next interface. func (e *GrantExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } if e.done { return nil } diff --git a/executor/index_lookup_join.go b/executor/index_lookup_join.go index 34a27e32c94e3..1bd93452941a5 100644 --- a/executor/index_lookup_join.go +++ b/executor/index_lookup_join.go @@ -190,11 +190,9 @@ func (e *IndexLookUpJoin) newInnerWorker(taskCh chan *lookUpJoinTask) *innerWork // Next implements the Executor interface. func (e *IndexLookUpJoin) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.Reset() e.joinResult.Reset() diff --git a/executor/insert.go b/executor/insert.go index 980d90f154cb2..932a2c09ce326 100644 --- a/executor/insert.go +++ b/executor/insert.go @@ -14,8 +14,6 @@ package executor import ( - "time" - "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/mysql" @@ -130,12 +128,6 @@ func (e *InsertExec) batchUpdateDupRows(newRows [][]types.Datum) error { // Next implements Exec Next interface. func (e *InsertExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.Reset() cols, err := e.getColumns(e.Table.Cols()) if err != nil { diff --git a/executor/join.go b/executor/join.go index 37366efb7d660..62704b7962cfa 100644 --- a/executor/join.go +++ b/executor/join.go @@ -509,11 +509,9 @@ func (e *HashJoinExec) join2Chunk(workerID uint, outerChk *chunk.Chunk, joinResu // step 1. fetch data from inner child and build a hash table; // step 2. fetch data from outer child in a background goroutine and probe the hash table in multiple join workers. func (e *HashJoinExec) Next(ctx context.Context, chk *chunk.Chunk) (err error) { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } if !e.prepared { e.innerFinished = make(chan error, 1) @@ -728,11 +726,9 @@ func (e *NestedLoopApplyExec) fetchAllInners(ctx context.Context) error { // Next implements the Executor interface. func (e *NestedLoopApplyExec) Next(ctx context.Context, chk *chunk.Chunk) (err error) { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.Reset() for { diff --git a/executor/load_data.go b/executor/load_data.go index 08007f8c33727..d6ee3724a3a74 100644 --- a/executor/load_data.go +++ b/executor/load_data.go @@ -17,7 +17,6 @@ import ( "bytes" "fmt" "strings" - "time" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/sessionctx" @@ -51,12 +50,6 @@ func NewLoadDataInfo(ctx sessionctx.Context, row []types.Datum, tbl table.Table, // Next implements the Executor Next interface. func (e *LoadDataExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.GrowAndReset(e.maxChunkSize) // TODO: support load data without local field. if !e.IsLocal { diff --git a/executor/load_stats.go b/executor/load_stats.go index 2e5058ffe6203..5b5c6aacf4dd7 100644 --- a/executor/load_stats.go +++ b/executor/load_stats.go @@ -15,8 +15,6 @@ package executor import ( "encoding/json" - "time" - "github.com/pingcap/tidb/domain" "github.com/pingcap/tidb/sessionctx" "github.com/pingcap/tidb/statistics" @@ -52,12 +50,6 @@ const LoadStatsVarKey loadStatsVarKeyType = 0 // Next implements the Executor Next interface. func (e *LoadStatsExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.GrowAndReset(e.maxChunkSize) if len(e.info.Path) == 0 { return errors.New("Load Stats: file path is empty") diff --git a/executor/merge_join.go b/executor/merge_join.go index f2f05214c60fc..438d57a144333 100644 --- a/executor/merge_join.go +++ b/executor/merge_join.go @@ -263,11 +263,9 @@ func (e *MergeJoinExec) prepare(ctx context.Context, chk *chunk.Chunk) error { // Next implements the Executor Next interface. func (e *MergeJoinExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.Reset() if !e.prepared { diff --git a/executor/prepared.go b/executor/prepared.go index c5939c83f01a7..a006bf0d6edd3 100644 --- a/executor/prepared.go +++ b/executor/prepared.go @@ -16,7 +16,6 @@ package executor import ( "math" "sort" - "time" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/expression" @@ -96,12 +95,6 @@ func NewPrepareExec(ctx sessionctx.Context, is infoschema.InfoSchema, sqlTxt str // Next implements the Executor Next interface. func (e *PrepareExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } vars := e.ctx.GetSessionVars() if e.ID != 0 { // Must be the case when we retry a prepare. @@ -200,12 +193,6 @@ type ExecuteExec struct { // Next implements the Executor Next interface. func (e *ExecuteExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } return nil } @@ -241,12 +228,6 @@ type DeallocateExec struct { // Next implements the Executor Next interface. func (e *DeallocateExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } vars := e.ctx.GetSessionVars() id, ok := vars.PreparedStmtNameToID[e.Name] if !ok { diff --git a/executor/projection.go b/executor/projection.go index d12d7f9e9fb55..d7d8ad0ab0864 100644 --- a/executor/projection.go +++ b/executor/projection.go @@ -141,11 +141,9 @@ func (e *ProjectionExec) Open(ctx context.Context) error { // +------------------------------+ +----------------------+ // func (e *ProjectionExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.GrowAndReset(e.maxChunkSize) if e.isUnparallelExec() { diff --git a/executor/replace.go b/executor/replace.go index 4367a39dc8d53..dbe79cfde4817 100644 --- a/executor/replace.go +++ b/executor/replace.go @@ -14,8 +14,6 @@ package executor import ( - "time" - "github.com/pingcap/tidb/table/tables" "github.com/pingcap/tidb/tablecodec" "github.com/pingcap/tidb/types" @@ -179,12 +177,6 @@ func (e *ReplaceExec) exec(newRows [][]types.Datum) error { // Next implements the Executor Next interface. func (e *ReplaceExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.Reset() cols, err := e.getColumns(e.Table.Cols()) if err != nil { diff --git a/executor/revoke.go b/executor/revoke.go index fb9adb15881be..4cbc10421da67 100644 --- a/executor/revoke.go +++ b/executor/revoke.go @@ -15,8 +15,6 @@ package executor import ( "fmt" - "time" - "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/domain" "github.com/pingcap/tidb/infoschema" @@ -53,12 +51,6 @@ type RevokeExec struct { // Next implements the Executor Next interface. func (e *RevokeExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } if e.done { return nil } diff --git a/executor/set.go b/executor/set.go index 8e948bebe7049..76562a6a4f8f9 100644 --- a/executor/set.go +++ b/executor/set.go @@ -43,12 +43,6 @@ type SetExecutor struct { // Next implements the Executor Next interface. func (e *SetExecutor) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.Reset() if e.done { return nil diff --git a/executor/show.go b/executor/show.go index 1960bde14cba7..0a76e27f683f7 100644 --- a/executor/show.go +++ b/executor/show.go @@ -64,12 +64,6 @@ type ShowExec struct { // Next implements the Executor Next interface. func (e *ShowExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.GrowAndReset(e.maxChunkSize) if e.result == nil { e.result = e.newFirstChunk() diff --git a/executor/simple.go b/executor/simple.go index 5499e803dd6f8..e05f20012260d 100644 --- a/executor/simple.go +++ b/executor/simple.go @@ -16,7 +16,6 @@ package executor import ( "fmt" "strings" - "time" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/config" @@ -50,12 +49,6 @@ type SimpleExec struct { // Next implements the Executor Next interface. func (e *SimpleExec) Next(ctx context.Context, chk *chunk.Chunk) (err error) { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } if e.done { return nil } diff --git a/executor/sort.go b/executor/sort.go index aa3ff46e7f8ad..56f0036f42100 100644 --- a/executor/sort.go +++ b/executor/sort.go @@ -74,11 +74,9 @@ func (e *SortExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *SortExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.Reset() if !e.fetched { @@ -303,11 +301,9 @@ func (e *TopNExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (e *TopNExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.Reset() if !e.fetched { diff --git a/executor/table_reader.go b/executor/table_reader.go index d9053460107de..9b4ffa47c41aa 100644 --- a/executor/table_reader.go +++ b/executor/table_reader.go @@ -100,11 +100,9 @@ func (e *TableReaderExecutor) Open(ctx context.Context) error { // Next fills data into the chunk passed by its caller. // The task was actually done by tableReaderHandler. func (e *TableReaderExecutor) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { + if e.runtimeStat != nil { start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } if err := e.resultHandler.nextChunk(ctx, chk); err != nil { e.feedback.Invalidate() diff --git a/executor/trace.go b/executor/trace.go index 872109ab9837a..fd6db06e6346d 100644 --- a/executor/trace.go +++ b/executor/trace.go @@ -45,12 +45,6 @@ type TraceExec struct { // Next executes real query and collects span later. func (e *TraceExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.Reset() if e.exhausted { return nil diff --git a/executor/union_scan.go b/executor/union_scan.go index a64e1c7991439..86bb4405b817a 100644 --- a/executor/union_scan.go +++ b/executor/union_scan.go @@ -126,11 +126,9 @@ func (us *UnionScanExec) Open(ctx context.Context) error { // Next implements the Executor Next interface. func (us *UnionScanExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if us.execStat != nil { + if us.runtimeStat != nil { start := time.Now() - defer func() { - us.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() + defer us.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) } chk.GrowAndReset(us.maxChunkSize) mutableRow := chunk.MutRowFromTypes(us.retTypes()) diff --git a/executor/update.go b/executor/update.go index 72865918b5e6a..de60b92ab8a01 100644 --- a/executor/update.go +++ b/executor/update.go @@ -14,8 +14,6 @@ package executor import ( - "time" - "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/model" @@ -114,12 +112,6 @@ func (e *UpdateExec) canNotUpdate(handle types.Datum) bool { // Next implements the Executor Next interface. func (e *UpdateExec) Next(ctx context.Context, chk *chunk.Chunk) error { - if e.execStat != nil { - start := time.Now() - defer func() { - e.execStat.Record(time.Now().Sub(start), chk.NumRows()) - }() - } chk.Reset() if !e.fetched { err := e.fetchChunkRows(ctx) diff --git a/planner/core/common_plans.go b/planner/core/common_plans.go index be81862b7979b..16e7c3cad1388 100644 --- a/planner/core/common_plans.go +++ b/planner/core/common_plans.go @@ -448,11 +448,11 @@ func (e *Explain) prepareOperatorInfo(p PhysicalPlan, taskType string, indent st count := string(strconv.AppendFloat([]byte{}, p.statsInfo().RowCount, 'f', 2, 64)) row := []string{e.prettyIdentifier(p.ExplainID(), indent, isLastChild), count, taskType, operatorInfo} if e.Analyze { - execStat := e.ctx.GetSessionVars().StmtCtx.ExecStats + execStat := e.ctx.GetSessionVars().StmtCtx.RuntimeStats if taskType == "cop" { row = append(row, "") //TODO: wait collect resp from tikv } else { - row = append(row, execStat.GetExecStat(p.ExplainID()).String()) + row = append(row, execStat.GetRuntimeStat(p.ExplainID()).String()) } } e.Rows = append(e.Rows, row) diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index ef9b458c1697c..4b6aeeae68f28 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -1482,7 +1482,7 @@ func (b *PlanBuilder) buildExplain(explain *ast.ExplainStmt) (Plan, error) { p.explainedPlans = map[int]bool{} p.explainPlanInRowFormat(p.StmtPlan.(PhysicalPlan), "root", "", true) if explain.Analyze { - b.ctx.GetSessionVars().StmtCtx.ExecStats = nil + b.ctx.GetSessionVars().StmtCtx.RuntimeStats = nil } case ast.ExplainFormatDOT: retFields := []string{"dot contents"} diff --git a/sessionctx/stmtctx/stmtctx.go b/sessionctx/stmtctx/stmtctx.go index c2456ab4bff7c..c3739585b1487 100644 --- a/sessionctx/stmtctx/stmtctx.go +++ b/sessionctx/stmtctx/stmtctx.go @@ -77,7 +77,7 @@ type StatementContext struct { Priority mysql.PriorityEnum NotFillCache bool MemTracker *memory.Tracker - ExecStats execdetails.ExecStats + RuntimeStats execdetails.RuntimeStats TableIDs []int64 IndexIDs []int64 } diff --git a/util/execdetails/execdetails.go b/util/execdetails/execdetails.go index 10afd3db4cc37..84ea8b0bd9da9 100644 --- a/util/execdetails/execdetails.go +++ b/util/execdetails/execdetails.go @@ -55,35 +55,38 @@ func (d ExecDetails) String() string { return strings.Join(parts, " ") } -// ExecStats collects executors's execution info. -type ExecStats map[string]*ExecStat +// RuntimeStats collects executors's execution info. +type RuntimeStats map[string]*RuntimeStat -// ExecStat collects one executor's execution info. -type ExecStat struct { - loop int32 +// RuntimeStat collects one executor's execution info. +type RuntimeStat struct { + // executor's Next() called times. + loop int32 + // executor consume time. consume int64 - rows int64 + // executor return row count. + rows int64 } -// NewExecutorStats creates new executor collector. -func NewExecutorStats() ExecStats { - return ExecStats(make(map[string]*ExecStat)) +// NewRuntimeStats creates new executor collector. +func NewRuntimeStats() RuntimeStats { + return RuntimeStats(make(map[string]*RuntimeStat)) } -// GetExecStat gets execStat for a executor. -func (e ExecStats) GetExecStat(planID string) *ExecStat { +// GetRuntimeStat gets execStat for a executor. +func (e RuntimeStats) GetRuntimeStat(planID string) *RuntimeStat { if e == nil { return nil } execStat, exists := e[planID] if !exists { - execStat = &ExecStat{} + execStat = &RuntimeStat{} e[planID] = execStat } return execStat } -func (e ExecStats) String() string { +func (e RuntimeStats) String() string { var buff bytes.Buffer buff.WriteString("(") for planID, stat := range e { @@ -94,13 +97,13 @@ func (e ExecStats) String() string { } // Record records executor's execution. -func (e *ExecStat) Record(d time.Duration, rowNum int) { +func (e *RuntimeStat) Record(d time.Duration, rowNum int) { atomic.AddInt32(&e.loop, 1) atomic.AddInt64(&e.consume, int64(d)) atomic.AddInt64(&e.rows, int64(rowNum)) } -func (e *ExecStat) String() string { +func (e *RuntimeStat) String() string { if e == nil { return "" } From 2873ff115fc266848ed5df320c33309350aaf49d Mon Sep 17 00:00:00 2001 From: lysu Date: Thu, 11 Oct 2018 20:47:25 +0800 Subject: [PATCH 4/7] rename some variable --- planner/core/common_plans.go | 4 ++-- util/execdetails/execdetails.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/planner/core/common_plans.go b/planner/core/common_plans.go index 16e7c3cad1388..c9ca1792ace73 100644 --- a/planner/core/common_plans.go +++ b/planner/core/common_plans.go @@ -448,11 +448,11 @@ func (e *Explain) prepareOperatorInfo(p PhysicalPlan, taskType string, indent st count := string(strconv.AppendFloat([]byte{}, p.statsInfo().RowCount, 'f', 2, 64)) row := []string{e.prettyIdentifier(p.ExplainID(), indent, isLastChild), count, taskType, operatorInfo} if e.Analyze { - execStat := e.ctx.GetSessionVars().StmtCtx.RuntimeStats + runtimeStat := e.ctx.GetSessionVars().StmtCtx.RuntimeStats if taskType == "cop" { row = append(row, "") //TODO: wait collect resp from tikv } else { - row = append(row, execStat.GetRuntimeStat(p.ExplainID()).String()) + row = append(row, runtimeStat.GetRuntimeStat(p.ExplainID()).String()) } } e.Rows = append(e.Rows, row) diff --git a/util/execdetails/execdetails.go b/util/execdetails/execdetails.go index 84ea8b0bd9da9..3eb55c9a47702 100644 --- a/util/execdetails/execdetails.go +++ b/util/execdetails/execdetails.go @@ -78,12 +78,12 @@ func (e RuntimeStats) GetRuntimeStat(planID string) *RuntimeStat { if e == nil { return nil } - execStat, exists := e[planID] + runtimecStat, exists := e[planID] if !exists { - execStat = &RuntimeStat{} - e[planID] = execStat + runtimecStat = &RuntimeStat{} + e[planID] = runtimecStat } - return execStat + return runtimecStat } func (e RuntimeStats) String() string { From cd6e960ea545cca06ba938f8a21c22ab5e324f39 Mon Sep 17 00:00:00 2001 From: lysu Date: Fri, 12 Oct 2018 11:04:48 +0800 Subject: [PATCH 5/7] fix defer bug --- executor/aggregate.go | 4 ++-- executor/distsql.go | 4 ++-- executor/executor.go | 14 +++++++------- executor/index_lookup_join.go | 2 +- executor/join.go | 4 ++-- executor/merge_join.go | 2 +- executor/projection.go | 2 +- executor/sort.go | 4 ++-- executor/table_reader.go | 2 +- executor/union_scan.go | 2 +- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/executor/aggregate.go b/executor/aggregate.go index 1959e298dd77d..c9b148e027901 100644 --- a/executor/aggregate.go +++ b/executor/aggregate.go @@ -504,7 +504,7 @@ func (w *HashAggFinalWorker) run(ctx sessionctx.Context, waitGroup *sync.WaitGro func (e *HashAggExec) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.Reset() if e.isUnparallelExec { @@ -763,7 +763,7 @@ func (e *StreamAggExec) Close() error { func (e *StreamAggExec) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.Reset() for !e.executed && chk.NumRows() < e.maxChunkSize { diff --git a/executor/distsql.go b/executor/distsql.go index 6c4f40efc3769..0553fb9658e12 100644 --- a/executor/distsql.go +++ b/executor/distsql.go @@ -246,7 +246,7 @@ func (e *IndexReaderExecutor) Close() error { func (e *IndexReaderExecutor) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } err := e.result.Next(ctx, chk) if err != nil { @@ -520,7 +520,7 @@ func (e *IndexLookUpExecutor) Close() error { func (e *IndexLookUpExecutor) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.Reset() for { diff --git a/executor/executor.go b/executor/executor.go index 2a00464f011a8..9e39bf2daeec8 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -179,7 +179,7 @@ type CancelDDLJobsExec struct { func (e *CancelDDLJobsExec) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.GrowAndReset(e.maxChunkSize) if e.cursor >= len(e.jobIDs) { @@ -625,7 +625,7 @@ type LimitExec struct { func (e *LimitExec) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.Reset() if e.cursor >= e.end { @@ -748,7 +748,7 @@ func (e *TableDualExec) Open(ctx context.Context) error { func (e *TableDualExec) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.Reset() if e.numReturned >= e.numDualRows { @@ -803,7 +803,7 @@ func (e *SelectionExec) Close() error { func (e *SelectionExec) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.GrowAndReset(e.maxChunkSize) @@ -882,7 +882,7 @@ type TableScanExec struct { func (e *TableScanExec) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.GrowAndReset(e.maxChunkSize) if e.isVirtualTable { @@ -986,7 +986,7 @@ func (e *MaxOneRowExec) Open(ctx context.Context) error { func (e *MaxOneRowExec) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.Reset() if e.evaluated { @@ -1132,7 +1132,7 @@ func (e *UnionExec) resultPuller(ctx context.Context, childID int) { func (e *UnionExec) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.GrowAndReset(e.maxChunkSize) if !e.initialized { diff --git a/executor/index_lookup_join.go b/executor/index_lookup_join.go index 1bd93452941a5..5585e119209cb 100644 --- a/executor/index_lookup_join.go +++ b/executor/index_lookup_join.go @@ -192,7 +192,7 @@ func (e *IndexLookUpJoin) newInnerWorker(taskCh chan *lookUpJoinTask) *innerWork func (e *IndexLookUpJoin) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.Reset() e.joinResult.Reset() diff --git a/executor/join.go b/executor/join.go index 62704b7962cfa..c8bb23a47f9f1 100644 --- a/executor/join.go +++ b/executor/join.go @@ -511,7 +511,7 @@ func (e *HashJoinExec) join2Chunk(workerID uint, outerChk *chunk.Chunk, joinResu func (e *HashJoinExec) Next(ctx context.Context, chk *chunk.Chunk) (err error) { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } if !e.prepared { e.innerFinished = make(chan error, 1) @@ -728,7 +728,7 @@ func (e *NestedLoopApplyExec) fetchAllInners(ctx context.Context) error { func (e *NestedLoopApplyExec) Next(ctx context.Context, chk *chunk.Chunk) (err error) { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.Reset() for { diff --git a/executor/merge_join.go b/executor/merge_join.go index 438d57a144333..e89c965621b2b 100644 --- a/executor/merge_join.go +++ b/executor/merge_join.go @@ -265,7 +265,7 @@ func (e *MergeJoinExec) prepare(ctx context.Context, chk *chunk.Chunk) error { func (e *MergeJoinExec) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.Reset() if !e.prepared { diff --git a/executor/projection.go b/executor/projection.go index d7d8ad0ab0864..a4cabf30547f2 100644 --- a/executor/projection.go +++ b/executor/projection.go @@ -143,7 +143,7 @@ func (e *ProjectionExec) Open(ctx context.Context) error { func (e *ProjectionExec) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.GrowAndReset(e.maxChunkSize) if e.isUnparallelExec() { diff --git a/executor/sort.go b/executor/sort.go index 56f0036f42100..d9f0ef9381c39 100644 --- a/executor/sort.go +++ b/executor/sort.go @@ -76,7 +76,7 @@ func (e *SortExec) Open(ctx context.Context) error { func (e *SortExec) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.Reset() if !e.fetched { @@ -303,7 +303,7 @@ func (e *TopNExec) Open(ctx context.Context) error { func (e *TopNExec) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.Reset() if !e.fetched { diff --git a/executor/table_reader.go b/executor/table_reader.go index 9b4ffa47c41aa..a2b27848bd350 100644 --- a/executor/table_reader.go +++ b/executor/table_reader.go @@ -102,7 +102,7 @@ func (e *TableReaderExecutor) Open(ctx context.Context) error { func (e *TableReaderExecutor) Next(ctx context.Context, chk *chunk.Chunk) error { if e.runtimeStat != nil { start := time.Now() - defer e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { e.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } if err := e.resultHandler.nextChunk(ctx, chk); err != nil { e.feedback.Invalidate() diff --git a/executor/union_scan.go b/executor/union_scan.go index 86bb4405b817a..5722e04803814 100644 --- a/executor/union_scan.go +++ b/executor/union_scan.go @@ -128,7 +128,7 @@ func (us *UnionScanExec) Open(ctx context.Context) error { func (us *UnionScanExec) Next(ctx context.Context, chk *chunk.Chunk) error { if us.runtimeStat != nil { start := time.Now() - defer us.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) + defer func() { us.runtimeStat.Record(time.Now().Sub(start), chk.NumRows()) }() } chk.GrowAndReset(us.maxChunkSize) mutableRow := chunk.MutRowFromTypes(us.retTypes()) From 0de7f6e23ae73b9e67c907730bceb3b969e692eb Mon Sep 17 00:00:00 2001 From: lysu Date: Fri, 12 Oct 2018 19:24:33 +0800 Subject: [PATCH 6/7] address comment --- executor/load_stats.go | 1 + executor/prepared_test.go | 4 ++++ executor/revoke.go | 1 + 3 files changed, 6 insertions(+) diff --git a/executor/load_stats.go b/executor/load_stats.go index 5b5c6aacf4dd7..968d3b10e0601 100644 --- a/executor/load_stats.go +++ b/executor/load_stats.go @@ -15,6 +15,7 @@ package executor import ( "encoding/json" + "github.com/pingcap/tidb/domain" "github.com/pingcap/tidb/sessionctx" "github.com/pingcap/tidb/statistics" diff --git a/executor/prepared_test.go b/executor/prepared_test.go index 1e804c2a24799..1040bf42521e9 100644 --- a/executor/prepared_test.go +++ b/executor/prepared_test.go @@ -178,6 +178,10 @@ func (s *testSuite) TestPrepared(c *C) { _, _, fields, err = tk.Se.PrepareStmt("update prepare3 set a = ?") c.Assert(err, IsNil) c.Assert(len(fields), Equals, 0) + + exec := &executor.ExecuteExec{} + exec.Next(ctx, nil) + exec.Close() } } diff --git a/executor/revoke.go b/executor/revoke.go index 4cbc10421da67..3f2edb6c7249b 100644 --- a/executor/revoke.go +++ b/executor/revoke.go @@ -15,6 +15,7 @@ package executor import ( "fmt" + "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/domain" "github.com/pingcap/tidb/infoschema" From a1b68b41cc72a7cdd16f9344188035f623dfba29 Mon Sep 17 00:00:00 2001 From: lysu Date: Fri, 12 Oct 2018 19:27:07 +0800 Subject: [PATCH 7/7] address comment --- executor/prepared_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/executor/prepared_test.go b/executor/prepared_test.go index 1040bf42521e9..3e19ca79b9e95 100644 --- a/executor/prepared_test.go +++ b/executor/prepared_test.go @@ -179,6 +179,7 @@ func (s *testSuite) TestPrepared(c *C) { c.Assert(err, IsNil) c.Assert(len(fields), Equals, 0) + // Coverage. exec := &executor.ExecuteExec{} exec.Next(ctx, nil) exec.Close()