Skip to content

Commit

Permalink
feat: fix and refine execution plan (#1568)
Browse files Browse the repository at this point in the history
  • Loading branch information
baurine authored Aug 14, 2023
1 parent e09fcd4 commit 9752633
Show file tree
Hide file tree
Showing 19 changed files with 740 additions and 277 deletions.
13 changes: 8 additions & 5 deletions pkg/apiserver/slowquery/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,10 @@ type Model struct {
TxnStartTS string `gorm:"column:Txn_start_ts" json:"txn_start_ts"`

// Detail
PrevStmt string `gorm:"column:Prev_stmt" json:"prev_stmt"`
Plan string `gorm:"column:Plan" json:"plan"` // deprecated, replaced by BinaryPlanText
BinaryPlan string `gorm:"column:Binary_plan" json:"binary_plan"`
BinaryPlanText string `gorm:"column:Binary_plan_text" proj:"tidb_decode_binary_plan(Binary_plan)" json:"binary_plan_text"`
Warnings datatypes.JSON `gorm:"column:Warnings" json:"warnings"`
PrevStmt string `gorm:"column:Prev_stmt" json:"prev_stmt"`
Plan string `gorm:"column:Plan" json:"plan"` // deprecated, replaced by BinaryPlanText
BinaryPlan string `gorm:"column:Binary_plan" json:"binary_plan"`
Warnings datatypes.JSON `gorm:"column:Warnings" json:"warnings"`

// Basic
IsInternal int `gorm:"column:Is_internal" json:"is_internal"`
Expand Down Expand Up @@ -96,6 +95,10 @@ type Model struct {
RocksdbBlockCacheHitCount uint `gorm:"column:Rocksdb_block_cache_hit_count" json:"rocksdb_block_cache_hit_count"`
RocksdbBlockReadCount uint `gorm:"column:Rocksdb_block_read_count" json:"rocksdb_block_read_count"`
RocksdbBlockReadByte uint `gorm:"column:Rocksdb_block_read_byte" json:"rocksdb_block_read_byte"`

// Computed fields
BinaryPlanJSON string `json:"binary_plan_json"` // binary plan json format
BinaryPlanText string `json:"binary_plan_text"` // binary plan plain text
}

type Field struct {
Expand Down
10 changes: 1 addition & 9 deletions pkg/apiserver/slowquery/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,11 @@ func QuerySlowLogList(req *GetListRequest, sysSchema *utils.SysSchema, db *gorm.
func QuerySlowLogDetail(req *GetDetailRequest, db *gorm.DB) (*Model, error) {
var result Model
err := db.
Select("*, (UNIX_TIMESTAMP(Time) + 0E0) AS timestamp, tidb_decode_binary_plan(Binary_plan) AS Binary_plan_text").
Select("*, (UNIX_TIMESTAMP(Time) + 0E0) AS timestamp").
Where("Digest = ?", req.Digest).
Where("Time = FROM_UNIXTIME(?)", req.Timestamp).
Where("Conn_id = ?", req.ConnectID).
First(&result).Error
if err != nil {
err = db.
Select("*, (UNIX_TIMESTAMP(Time) + 0E0) AS timestamp").
Where("Digest = ?", req.Digest).
Where("Time = FROM_UNIXTIME(?)", req.Timestamp).
Where("Conn_id = ?", req.ConnectID).
First(&result).Error
}
if err != nil {
return nil, err
}
Expand Down
13 changes: 11 additions & 2 deletions pkg/apiserver/slowquery/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,23 @@ func (s *Service) getDetails(c *gin.Context) {
return
}

// generate binary plan
// generate binary plan json
//
// Due to a kernel bug, the binary plan may fail to parse due to
// encoding issues. Additionally, since the binary plan field is
// not a required field, we can mask this error.
//
// See: https://github.com/pingcap/tidb-dashboard/issues/1515
result.BinaryPlan, _ = utils.GenerateBinaryPlanJSON(result.BinaryPlan)
if result.BinaryPlan != "" {
// may failed but it's ok
result.BinaryPlanText, _ = utils.GenerateBinaryPlanText(db, result.BinaryPlan)
// may failed but it's ok
result.BinaryPlanJSON, _ = utils.GenerateBinaryPlanJSON(result.BinaryPlan)

// reduce response size
result.BinaryPlan = ""
result.Plan = ""
}

c.JSON(http.StatusOK, *result)
}
Expand Down
5 changes: 3 additions & 2 deletions pkg/apiserver/statement/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,8 @@ type Model struct {
AggIndexNames string `json:"index_names" agg:"ANY_VALUE(index_names)"`
AggPlanCount int `json:"plan_count" agg:"COUNT(DISTINCT plan_digest)" related:"plan_digest"`
AggPlan string `json:"plan" agg:"ANY_VALUE(plan)"` // deprecated, replaced by BinaryPlanText
AggPlanDigest string `json:"plan_digest" agg:"ANY_VALUE(plan_digest)"`
AggBinaryPlan string `json:"binary_plan" agg:"ANY_VALUE(binary_plan)"`
AggBinaryPlanText string `json:"binary_plan_text" related:"binary_plan" agg:"tidb_decode_binary_plan(ANY_VALUE(binary_plan))"`
AggPlanDigest string `json:"plan_digest" agg:"ANY_VALUE(plan_digest)"`
AggPlanHint *string `json:"plan_hint" agg:"ANY_VALUE(plan_hint)"`
// RocksDB
AggMaxRocksdbDeleteSkippedCount uint `json:"max_rocksdb_delete_skipped_count" agg:"MAX(max_rocksdb_delete_skipped_count)"`
Expand All @@ -99,6 +98,8 @@ type Model struct {
// Computed fields
RelatedSchemas string `json:"related_schemas"`
PlanCanBeBound bool `json:"plan_can_be_bound"`
BinaryPlanJSON string `json:"binary_plan_json"`
BinaryPlanText string `json:"binary_plan_text"`
}

// tableNames example: "d1.a1,d2.a2,d1.a1,d3.a3"
Expand Down
50 changes: 30 additions & 20 deletions pkg/apiserver/statement/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,27 +44,30 @@ func newService(p ServiceParams, ff *featureflag.Registry) *Service {

func registerRouter(r *gin.RouterGroup, auth *user.AuthService, s *Service) {
endpoint := r.Group("/statements")
endpoint.Use(auth.MWAuthRequired())
endpoint.Use(utils.MWConnectTiDB(s.params.TiDBClient))
{
endpoint.GET("/download", s.downloadHandler)
endpoint.POST("/download/token", s.downloadTokenHandler)

endpoint.GET("/config", s.configHandler)
endpoint.POST("/config", auth.MWRequireWritePriv(), s.modifyConfigHandler)
endpoint.GET("/stmt_types", s.stmtTypesHandler)
endpoint.GET("/list", s.listHandler)
endpoint.GET("/plans", s.plansHandler)
endpoint.GET("/plan/detail", s.planDetailHandler)

endpoint.GET("/available_fields", s.getAvailableFields)

binding := endpoint.Group("/plan/binding")
binding.Use(s.planBindingFeatureFlag.VersionGuard())
endpoint.Use(auth.MWAuthRequired())
endpoint.Use(utils.MWConnectTiDB(s.params.TiDBClient))
{
binding.GET("", s.getPlanBindingHandler)
binding.POST("", s.createPlanBindingHandler)
binding.DELETE("", s.dropPlanBindingHandler)
endpoint.POST("/download/token", s.downloadTokenHandler)

endpoint.GET("/config", s.configHandler)
endpoint.POST("/config", auth.MWRequireWritePriv(), s.modifyConfigHandler)
endpoint.GET("/stmt_types", s.stmtTypesHandler)
endpoint.GET("/list", s.listHandler)
endpoint.GET("/plans", s.plansHandler)
endpoint.GET("/plan/detail", s.planDetailHandler)

endpoint.GET("/available_fields", s.getAvailableFields)

binding := endpoint.Group("/plan/binding")
binding.Use(s.planBindingFeatureFlag.VersionGuard())
{
binding.GET("", s.getPlanBindingHandler)
binding.POST("", s.createPlanBindingHandler)
binding.DELETE("", s.dropPlanBindingHandler)
}
}
}
}
Expand Down Expand Up @@ -230,9 +233,16 @@ func (s *Service) planDetailHandler(c *gin.Context) {
return
}

// get binary plan
// may failed but it's ok
result.AggBinaryPlan, _ = utils.GenerateBinaryPlanJSON(result.AggBinaryPlan)
if result.AggBinaryPlan != "" {
// may failed but it's ok
result.BinaryPlanText, _ = utils.GenerateBinaryPlanText(db, result.AggBinaryPlan)
// may failed but it's ok
result.BinaryPlanJSON, _ = utils.GenerateBinaryPlanJSON(result.AggBinaryPlan)

// reduce response size
result.AggBinaryPlan = ""
result.AggPlan = ""
}

c.JSON(http.StatusOK, result)
}
Expand Down
15 changes: 15 additions & 0 deletions pkg/apiserver/utils/binary_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/pingcap/tipb/go-tipb"
json "google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/runtime/protoimpl"
"gorm.io/gorm"
)

const (
Expand Down Expand Up @@ -975,3 +976,17 @@ func formatJSON(s string) (*simplejson.Json, error) {

return simplejson.NewJson([]byte(s))
}

/////////////////

func GenerateBinaryPlanText(db *gorm.DB, b string) (string, error) {
type binaryPlanText struct {
Text string `gorm:"column:binary_plan_text"`
}
ret := &binaryPlanText{}
err := db.Raw(fmt.Sprintf("select tidb_decode_binary_plan('%s') as binary_plan_text", b)).Find(ret).Error
if err != nil {
return "", err
}
return ret.Text, err
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ export interface SlowqueryModel {
*/
'binary_plan'?: string;
/**
*
* Computed fields
* @type {string}
* @memberof SlowqueryModel
*/
'binary_plan_json'?: string;
/**
* binary plan plain text
* @type {string}
* @memberof SlowqueryModel
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ export interface StatementModel {
* @memberof StatementModel
*/
'binary_plan'?: string;
/**
*
* @type {string}
* @memberof StatementModel
*/
'binary_plan_json'?: string;
/**
*
* @type {string}
Expand Down
8 changes: 8 additions & 0 deletions ui/packages/tidb-dashboard-client/swagger/spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -4906,7 +4906,12 @@
"binary_plan": {
"type": "string"
},
"binary_plan_json": {
"description": "Computed fields",
"type": "string"
},
"binary_plan_text": {
"description": "binary plan plain text",
"type": "string"
},
"commit_backoff_time": {
Expand Down Expand Up @@ -5314,6 +5319,9 @@
"binary_plan": {
"type": "string"
},
"binary_plan_json": {
"type": "string"
},
"binary_plan_text": {
"type": "string"
},
Expand Down
Loading

0 comments on commit 9752633

Please sign in to comment.