github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/explain/marshal_query.go (about) 1 // Copyright 2021 - 2022 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package explain 16 17 import ( 18 "bytes" 19 "context" 20 "fmt" 21 "strconv" 22 "strings" 23 24 "github.com/matrixorigin/matrixone/pkg/common/moerr" 25 "github.com/matrixorigin/matrixone/pkg/pb/plan" 26 "github.com/matrixorigin/matrixone/pkg/util/trace/impl/motrace/statistic" 27 ) 28 29 var errUnsupportedNodeType = "Unsupported node type when plan is serialized to json" 30 31 // The global variable is used to serialize plan and avoid objects being repeatedly created 32 var MarshalPlanOptions = ExplainOptions{ 33 Verbose: true, 34 Analyze: true, 35 Format: EXPLAIN_FORMAT_TEXT, 36 } 37 38 func ConvertNode(ctx context.Context, node *plan.Node, options *ExplainOptions) (*Node, error) { 39 marshalNodeImpl := NewMarshalNodeImpl(node) 40 newNode := &Node{ 41 NodeId: strconv.FormatInt(int64(node.NodeId), 10), 42 Statistics: marshalNodeImpl.GetStatistics(ctx, options), 43 Stats: marshalNodeImpl.GetStats(), 44 TotalStats: marshalNodeImpl.GetTotalStats(), 45 } 46 name, err := marshalNodeImpl.GetNodeName(ctx) 47 if err != nil { 48 return nil, err 49 } 50 newNode.Name = name 51 52 title, err := marshalNodeImpl.GetNodeTitle(ctx, options) 53 if err != nil { 54 return nil, err 55 } 56 newNode.Title = title 57 58 labels, err := marshalNodeImpl.GetNodeLabels(ctx, options) 59 if err != nil { 60 return nil, err 61 } 62 newNode.Labels = labels 63 return newNode, nil 64 } 65 66 type MarshalNode interface { 67 GetNodeName(ctx context.Context) (string, error) 68 GetNodeTitle(ctx context.Context, options *ExplainOptions) (string, error) 69 GetNodeLabels(ctx context.Context, options *ExplainOptions) ([]Label, error) 70 GetStatistics(ctx context.Context, options *ExplainOptions) Statistics 71 GetStats() Stats 72 GetTotalStats() TotalStats 73 } 74 75 type MarshalNodeImpl struct { 76 node *plan.Node 77 } 78 79 func NewMarshalNodeImpl(node *plan.Node) *MarshalNodeImpl { 80 return &MarshalNodeImpl{ 81 node: node, 82 } 83 } 84 85 func (m MarshalNodeImpl) GetStats() Stats { 86 if m.node.Stats != nil { 87 var hashmapSize float64 88 if m.node.Stats.HashmapStats != nil { 89 hashmapSize = m.node.Stats.HashmapStats.HashmapSize 90 } 91 return Stats{ 92 BlockNum: m.node.Stats.BlockNum, 93 Cost: m.node.Stats.Cost, 94 Outcnt: m.node.Stats.Outcnt, 95 HashmapSize: hashmapSize, 96 Rowsize: m.node.Stats.Rowsize, 97 } 98 } else { 99 return Stats{} 100 } 101 } 102 103 func (m MarshalNodeImpl) GetNodeName(ctx context.Context) (string, error) { 104 // Get the Node Name 105 if value, ok := nodeTypeToNameMap[m.node.NodeType]; ok { 106 return value, nil 107 } else { 108 return "", moerr.NewInternalError(ctx, errUnsupportedNodeType) 109 } 110 } 111 112 func (m MarshalNodeImpl) GetNodeTitle(ctx context.Context, options *ExplainOptions) (string, error) { 113 //var result string 114 buf := bytes.NewBuffer(make([]byte, 0, 400)) 115 var err error 116 switch m.node.NodeType { 117 case plan.Node_TABLE_SCAN, plan.Node_EXTERNAL_SCAN, plan.Node_MATERIAL_SCAN, plan.Node_SOURCE_SCAN: 118 //"title" : "SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.DATE_DIM", 119 if m.node.ObjRef != nil { 120 buf.WriteString(m.node.ObjRef.GetSchemaName() + "." + m.node.ObjRef.GetObjName()) 121 } else if m.node.TableDef != nil { 122 buf.WriteString(m.node.TableDef.GetName()) 123 } else { 124 return "", moerr.NewInvalidInput(ctx, "Table definition not found when plan is serialized to json") 125 } 126 case plan.Node_DELETE: 127 if m.node.DeleteCtx != nil { 128 ctx := m.node.DeleteCtx.Ref 129 buf.WriteString(ctx.SchemaName + "." + ctx.ObjName) 130 } else { 131 return "", moerr.NewInternalError(ctx, "Table definition not found when plan is serialized to json") 132 } 133 case plan.Node_INSERT: 134 if m.node.InsertCtx != nil { 135 ctx := m.node.InsertCtx.Ref 136 buf.WriteString(ctx.SchemaName + "." + ctx.ObjName) 137 } else { 138 return "", moerr.NewInternalError(ctx, "Table definition not found when plan is serialized to json") 139 } 140 case plan.Node_PROJECT, plan.Node_VALUE_SCAN, plan.Node_UNION, plan.Node_UNION_ALL, 141 plan.Node_INTERSECT, plan.Node_INTERSECT_ALL, plan.Node_MINUS: 142 //"title" : "STORE.S_STORE_NAME,STORE.S_STORE_ID,WSS.D_WEEK_SEQ" 143 exprs := NewExprListDescribeImpl(m.node.ProjectList) 144 err = exprs.GetDescription(ctx, options, buf) 145 if err != nil { 146 return "", err 147 } 148 case plan.Node_AGG: 149 // "SUM(IFF(DATE_DIM.D_DAY_NAME = 'Sunday', STORE_SALES.SS_SALES_PRICE, null))" 150 exprs := NewExprListDescribeImpl(m.node.AggList) 151 err = exprs.GetDescription(ctx, options, buf) 152 if err != nil { 153 return "", err 154 } 155 case plan.Node_FILTER: 156 //"title" : "(D_0.D_MONTH_SEQ >= 1189) AND (D_0.D_MONTH_SEQ <= 1200)", 157 exprs := NewExprListDescribeImpl(m.node.FilterList) 158 err = exprs.GetDescription(ctx, options, buf) 159 if err != nil { 160 return "", err 161 } 162 case plan.Node_JOIN: 163 //"title" : "(DATE_DIM.D_DATE_SK = STORE_SALES.SS_SOLD_DATE_SK)", 164 exprs := NewExprListDescribeImpl(m.node.OnList) 165 err = exprs.GetDescription(ctx, options, buf) 166 if err != nil { 167 return "", err 168 } 169 case plan.Node_SORT: 170 //"title" : "STORE.S_STORE_NAME ASC NULLS LAST,STORE.S_STORE_ID ASC NULLS LAST,WSS.D_WEEK_SEQ ASC NULLS LAST", 171 orderByDescImpl := NewOrderByDescribeImpl(m.node.OrderBy) 172 err = orderByDescImpl.GetDescription(ctx, options, buf) 173 if err != nil { 174 return "", err 175 } 176 case plan.Node_PRE_INSERT: 177 return "preinsert", nil 178 case plan.Node_PRE_INSERT_UK: 179 return "preinsert_uk", nil 180 case plan.Node_PRE_INSERT_SK: 181 return "preinsert_sk", nil 182 case plan.Node_PRE_DELETE: 183 return "predelete", nil 184 case plan.Node_SINK: 185 return "sink", nil 186 case plan.Node_SINK_SCAN: 187 return "sink_scan", nil 188 case plan.Node_RECURSIVE_SCAN: 189 return "recursive_scan", nil 190 case plan.Node_RECURSIVE_CTE: 191 return "cte_scan", nil 192 case plan.Node_ON_DUPLICATE_KEY: 193 return "on_duplicate_key", nil 194 case plan.Node_LOCK_OP: 195 return "lock_op", nil 196 case plan.Node_ASSERT: 197 return "assert", nil 198 case plan.Node_BROADCAST: 199 return "broadcast", nil 200 case plan.Node_SPLIT: 201 return "split", nil 202 case plan.Node_GATHER: 203 return "gather", nil 204 case plan.Node_REPLACE: 205 return "replace", nil 206 case plan.Node_TIME_WINDOW: 207 return "time_window", nil 208 case plan.Node_FILL: 209 return "fill", nil 210 case plan.Node_PARTITION: 211 return "partition", nil 212 case plan.Node_FUNCTION_SCAN: 213 //"title" : "SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.DATE_DIM", 214 if m.node.TableDef != nil && m.node.TableDef.TblFunc != nil { 215 fmt.Fprintf(buf, "Table Function[%s]", m.node.TableDef.TblFunc.Name) 216 } else { 217 return "", moerr.NewInvalidInput(ctx, "Table definition not found when plan is serialized to json") 218 } 219 case plan.Node_FUZZY_FILTER: 220 return "fuzzy_filter", nil 221 case plan.Node_SAMPLE: 222 return "sample", nil 223 case plan.Node_UNKNOWN: 224 return "unknown", nil 225 case plan.Node_DISTINCT: 226 return "distinct", nil 227 case plan.Node_UNIQUE: 228 return "unique", nil 229 case plan.Node_MINUS_ALL: 230 return "minus_all", nil 231 case plan.Node_EXTERNAL_FUNCTION: 232 return "external_function", nil 233 case plan.Node_WINDOW: 234 return "window", nil 235 case plan.Node_MATERIAL: 236 return "mterial", nil 237 default: 238 return "", moerr.NewInternalError(ctx, errUnsupportedNodeType) 239 } 240 return strings.TrimSpace(buf.String()), nil 241 } 242 243 func (m MarshalNodeImpl) GetNodeLabels(ctx context.Context, options *ExplainOptions) ([]Label, error) { 244 labels := make([]Label, 0) 245 246 // 1. Handling unique label information for different nodes 247 switch m.node.NodeType { 248 case plan.Node_TABLE_SCAN, plan.Node_EXTERNAL_SCAN, plan.Node_MATERIAL_SCAN, plan.Node_SOURCE_SCAN: 249 tableDef := m.node.TableDef 250 objRef := m.node.ObjRef 251 fullTableName := "" 252 if objRef != nil { 253 fullTableName += objRef.GetSchemaName() + "." + objRef.GetObjName() 254 } else if tableDef != nil { 255 fullTableName += tableDef.GetName() 256 } else { 257 return nil, moerr.NewInternalError(ctx, "Table definition not found when plan is serialized to json") 258 } 259 260 labels = append(labels, Label{ 261 Name: Label_Table_Name, //"Full table name", 262 Value: fullTableName, 263 }) 264 265 // "name" : "Columns (2 / 28)", 266 columns := GetTableColsLableValue(ctx, tableDef.Cols, options) 267 268 labels = append(labels, Label{ 269 Name: Label_Table_Columns, //"Columns", 270 Value: columns, 271 }) 272 273 labels = append(labels, Label{ 274 Name: Label_Total_Columns, //"Total columns", 275 Value: len(tableDef.Name2ColIndex), 276 }) 277 278 labels = append(labels, Label{ 279 Name: Label_Scan_Columns, //"Scan columns", 280 Value: len(tableDef.Cols), 281 }) 282 283 if len(m.node.BlockFilterList) > 0 { 284 value, err := GetExprsLabelValue(ctx, m.node.BlockFilterList, options) 285 if err != nil { 286 return nil, err 287 } 288 labels = append(labels, Label{ 289 Name: Label_Block_Filter_Conditions, // "Block Filter conditions", 290 Value: value, 291 }) 292 } 293 case plan.Node_FUNCTION_SCAN: 294 tableDef := m.node.TableDef 295 fullTableName := "" 296 if tableDef != nil && tableDef.TblFunc != nil { 297 fullTableName += tableDef.TblFunc.GetName() 298 } else { 299 return nil, moerr.NewInternalError(ctx, "Table Function definition not found when plan is serialized to json") 300 } 301 302 labels = append(labels, Label{ 303 Name: Label_Table_Name, //"Full table name", 304 Value: fullTableName, 305 }) 306 307 // "name" : "Columns (2 / 28)", 308 columns := GetTableColsLableValue(ctx, tableDef.Cols, options) 309 310 labels = append(labels, Label{ 311 Name: Label_Table_Columns, //"Columns", 312 Value: columns, 313 }) 314 315 labels = append(labels, Label{ 316 Name: Label_Total_Columns, //"Total columns", 317 Value: len(tableDef.Name2ColIndex), 318 }) 319 320 labels = append(labels, Label{ 321 Name: Label_Scan_Columns, //"Scan columns", 322 Value: len(tableDef.Cols), 323 }) 324 325 if len(m.node.BlockFilterList) > 0 { 326 value, err := GetExprsLabelValue(ctx, m.node.BlockFilterList, options) 327 if err != nil { 328 return nil, err 329 } 330 labels = append(labels, Label{ 331 Name: Label_Block_Filter_Conditions, // "Block Filter conditions", 332 Value: value, 333 }) 334 } 335 case plan.Node_INSERT: 336 objRef := m.node.InsertCtx.Ref 337 fullTableName := "" 338 if objRef != nil { 339 fullTableName += objRef.GetSchemaName() + "." + objRef.GetObjName() 340 } else { 341 return nil, moerr.NewInternalError(ctx, "Table definition not found when plan is serialized to json") 342 } 343 344 labels = append(labels, Label{ 345 Name: Label_Table_Name, //"Full table name", 346 Value: fullTableName, 347 }) 348 case plan.Node_DELETE: 349 if m.node.DeleteCtx != nil { 350 deleteTableNames := GetDeleteTableLabelValue(m.node.DeleteCtx) 351 labels = append(labels, Label{ 352 Name: Label_Table_Name, //"Full table name", 353 Value: deleteTableNames, 354 }) 355 } else { 356 return nil, moerr.NewInvalidInput(ctx, "Table definition not found when plan is serialized to json") 357 } 358 case plan.Node_PROJECT: 359 value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options) 360 if err != nil { 361 return nil, err 362 } 363 labels = append(labels, Label{ 364 Name: Label_List_Expression, //"List of expressions", 365 Value: value, 366 }) 367 case plan.Node_AGG: 368 // Get Group key info 369 if len(m.node.GroupBy) > 0 { 370 // Get Grouping Key 371 value, err := GetExprsLabelValue(ctx, m.node.GroupBy, options) 372 if err != nil { 373 return nil, err 374 } 375 labels = append(labels, Label{ 376 Name: Label_Grouping_Keys, //"Grouping keys", 377 Value: value, 378 }) 379 } 380 381 // Get Aggregate function info 382 if len(m.node.AggList) > 0 { 383 value, err := GetExprsLabelValue(ctx, m.node.AggList, options) 384 if err != nil { 385 return nil, err 386 } 387 labels = append(labels, Label{ 388 Name: Label_Agg_Functions, //"Aggregate functions", 389 Value: value, 390 }) 391 } 392 case plan.Node_FILTER: 393 value, err := GetExprsLabelValue(ctx, m.node.FilterList, options) 394 if err != nil { 395 return nil, err 396 } 397 labels = append(labels, Label{ 398 Name: Label_Filter_Conditions, //"Filter conditions", 399 Value: value, 400 }) 401 case plan.Node_JOIN: 402 // Get Join type 403 labels = append(labels, Label{ 404 Name: Label_Join_Type, //"Join type", 405 Value: m.node.JoinType.String(), 406 }) 407 408 // Get Join Condition info 409 if len(m.node.OnList) > 0 { 410 value, err := GetExprsLabelValue(ctx, m.node.OnList, options) 411 if err != nil { 412 return nil, err 413 } 414 labels = append(labels, Label{ 415 Name: Label_Join_Conditions, //"Join conditions", 416 Value: value, 417 }) 418 } 419 labels = append(labels, Label{ 420 Name: Label_Left_NodeId, //"Left node id", 421 Value: m.node.Children[0], 422 }) 423 labels = append(labels, Label{ 424 Name: Label_Right_NodeId, //"Right node id", 425 Value: m.node.Children[1], 426 }) 427 case plan.Node_SORT: 428 result, err := GetOrderByLabelValue(ctx, m.node.OrderBy, options) 429 if err != nil { 430 return nil, err 431 } 432 labels = append(labels, Label{ 433 Name: Label_Sort_Keys, //"Sort keys", 434 Value: result, 435 }) 436 case plan.Node_VALUE_SCAN: 437 value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options) 438 if err != nil { 439 return nil, err 440 } 441 labels = append(labels, Label{ 442 Name: Label_List_Values, //"List of values", 443 Value: value, 444 }) 445 446 if len(m.node.BlockFilterList) > 0 { 447 value, err = GetExprsLabelValue(ctx, m.node.BlockFilterList, options) 448 if err != nil { 449 return nil, err 450 } 451 labels = append(labels, Label{ 452 Name: Label_Block_Filter_Conditions, // "Block Filter conditions", 453 Value: value, 454 }) 455 } 456 case plan.Node_UNION: 457 value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options) 458 if err != nil { 459 return nil, err 460 } 461 labels = append(labels, Label{ 462 Name: Label_Union_Expressions, //"Union expressions", 463 Value: value, 464 }) 465 case plan.Node_UNION_ALL: 466 value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options) 467 if err != nil { 468 return nil, err 469 } 470 labels = append(labels, Label{ 471 Name: Label_Union_All_Expressions, // "Union all expressions", 472 Value: value, 473 }) 474 case plan.Node_INTERSECT: 475 value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options) 476 if err != nil { 477 return nil, err 478 } 479 labels = append(labels, Label{ 480 Name: Label_Intersect_Expressions, //"Intersect expressions", 481 Value: value, 482 }) 483 case plan.Node_INTERSECT_ALL: 484 value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options) 485 if err != nil { 486 return nil, err 487 } 488 labels = append(labels, Label{ 489 Name: Label_Intersect_All_Expressions, //"Intersect All expressions", 490 Value: value, 491 }) 492 case plan.Node_MINUS: 493 value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options) 494 if err != nil { 495 return nil, err 496 } 497 labels = append(labels, Label{ 498 Name: Label_Minus_Expressions, //"Minus expressions", 499 Value: value, 500 }) 501 case plan.Node_PRE_INSERT: 502 labels = append(labels, Label{ 503 Name: Label_Pre_Insert, //"pre insert", 504 Value: []string{}, 505 }) 506 case plan.Node_PRE_INSERT_UK: 507 labels = append(labels, Label{ 508 Name: Label_Pre_InsertUk, //"pre insert uk", 509 Value: []string{}, 510 }) 511 case plan.Node_PRE_INSERT_SK: 512 labels = append(labels, Label{ 513 Name: Label_Pre_InsertSk, //"pre insert sk", 514 Value: []string{}, 515 }) 516 case plan.Node_PRE_DELETE: 517 labels = append(labels, Label{ 518 Name: Label_Pre_Delete, //"pre delete", 519 Value: []string{}, 520 }) 521 case plan.Node_SINK: 522 labels = append(labels, Label{ 523 Name: Label_Sink, //"sink", 524 Value: []string{}, 525 }) 526 case plan.Node_SINK_SCAN: 527 labels = append(labels, Label{ 528 Name: Label_Sink_Scan, //"sink scan", 529 Value: []string{}, 530 }) 531 case plan.Node_RECURSIVE_SCAN: 532 labels = append(labels, Label{ 533 Name: Label_Recursive_SCAN, //"sink scan", 534 Value: []string{}, 535 }) 536 case plan.Node_RECURSIVE_CTE: 537 labels = append(labels, Label{ 538 Name: Label_Recursive_SCAN, //"sink scan", 539 Value: []string{}, 540 }) 541 case plan.Node_LOCK_OP: 542 labels = append(labels, Label{ 543 Name: Label_Lock_Op, //"lock op", 544 Value: []string{}, 545 }) 546 case plan.Node_TIME_WINDOW: 547 labels = append(labels, Label{ 548 Name: Label_Time_Window, 549 Value: []string{}, 550 }) 551 case plan.Node_PARTITION: 552 labels = append(labels, Label{ 553 Name: Label_Partition, 554 Value: []string{}, 555 }) 556 case plan.Node_BROADCAST: 557 labels = append(labels, Label{ 558 Name: Label_Boardcast, 559 Value: []string{}, 560 }) 561 case plan.Node_SPLIT: 562 labels = append(labels, Label{ 563 Name: Label_Split, 564 Value: []string{}, 565 }) 566 case plan.Node_GATHER: 567 labels = append(labels, Label{ 568 Name: Label_Gather, 569 Value: []string{}, 570 }) 571 case plan.Node_ASSERT: 572 labels = append(labels, Label{ 573 Name: Label_Assert, 574 Value: []string{}, 575 }) 576 case plan.Node_ON_DUPLICATE_KEY: 577 labels = append(labels, Label{ 578 Name: Label_On_Duplicate_Key, 579 Value: []string{}, 580 }) 581 case plan.Node_FUZZY_FILTER: 582 labels = append(labels, Label{ 583 Name: Label_Fuzzy_Filter, 584 Value: []string{}, 585 }) 586 case plan.Node_EXTERNAL_FUNCTION: 587 labels = append(labels, Label{ 588 Name: Label_External_Function, 589 Value: []string{}, 590 }) 591 case plan.Node_FILL: 592 labels = append(labels, Label{ 593 Name: Label_Fill, 594 Value: []string{}, 595 }) 596 case plan.Node_DISTINCT: 597 labels = append(labels, Label{ 598 Name: Label_Distinct, 599 Value: []string{}, 600 }) 601 case plan.Node_SAMPLE: 602 labels = append(labels, Label{ 603 Name: Label_Sample, 604 Value: []string{}, 605 }) 606 case plan.Node_WINDOW: 607 labels = append(labels, Label{ 608 Name: Label_Window, 609 Value: []string{}, 610 }) 611 case plan.Node_MINUS_ALL: 612 labels = append(labels, Label{ 613 Name: Label_Minus_All, 614 Value: []string{}, 615 }) 616 case plan.Node_UNIQUE: 617 labels = append(labels, Label{ 618 Name: Label_Unique, 619 Value: []string{}, 620 }) 621 case plan.Node_REPLACE: 622 labels = append(labels, Label{ 623 Name: Label_Replace, 624 Value: []string{}, 625 }) 626 case plan.Node_UNKNOWN: 627 labels = append(labels, Label{ 628 Name: Label_Unknown, 629 Value: []string{}, 630 }) 631 case plan.Node_MATERIAL: 632 labels = append(labels, Label{ 633 Name: Label_Meterial, 634 Value: []string{}, 635 }) 636 default: 637 return nil, moerr.NewInternalError(ctx, errUnsupportedNodeType) 638 } 639 640 // 2. handle shared label information for all nodes, such as filter conditions 641 if len(m.node.FilterList) > 0 && m.node.NodeType != plan.Node_FILTER { 642 value, err := GetExprsLabelValue(ctx, m.node.FilterList, options) 643 if err != nil { 644 return nil, err 645 } 646 labels = append(labels, Label{ 647 Name: Label_Filter_Conditions, // "Filter conditions", 648 Value: value, 649 }) 650 } 651 652 // 3. handle `Limit` and `Offset` label information for all nodes 653 if m.node.Limit != nil { 654 buf := bytes.NewBuffer(make([]byte, 0, 80)) 655 err := describeExpr(ctx, m.node.Limit, options, buf) 656 if err != nil { 657 return nil, err 658 } 659 labels = append(labels, Label{ 660 Name: Label_Row_Number, //"Number of rows", 661 Value: buf.String(), 662 }) 663 664 if m.node.Offset != nil { 665 buf.Reset() 666 err := describeExpr(ctx, m.node.Offset, options, buf) 667 if err != nil { 668 return nil, err 669 } 670 labels = append(labels, Label{ 671 Name: Label_Offset, // "Offset", 672 Value: buf.String(), 673 }) 674 } else { 675 labels = append(labels, Label{ 676 Name: Label_Offset, // "Offset", 677 Value: 0, 678 }) 679 } 680 } 681 return labels, nil 682 } 683 684 const TimeConsumed = "Time Consumed" 685 const WaitTime = "Wait Time" 686 const ScanTime = "Scan Time" 687 const InsertTime = "Insert Time" 688 689 const InputRows = "Input Rows" 690 const OutputRows = "Output Rows" 691 const InputSize = "Input Size" 692 const OutputSize = "Output Size" 693 const MemorySize = "Memory Size" 694 const DiskIO = "Disk IO" 695 const S3IOByte = "S3 IO Byte" 696 const S3IOInputCount = "S3 IO Input Count" 697 const S3IOOutputCount = "S3 IO Output Count" 698 const Network = "Network" 699 700 func GetStatistic4Trace(ctx context.Context, node *plan.Node, options *ExplainOptions) (s statistic.StatsArray) { 701 s.Reset() 702 if options.Analyze && node.AnalyzeInfo != nil { 703 analyzeInfo := node.AnalyzeInfo 704 s.WithTimeConsumed(float64(analyzeInfo.TimeConsumed)). 705 WithMemorySize(float64(analyzeInfo.MemorySize)). 706 WithS3IOInputCount(float64(analyzeInfo.S3IOInputCount)). 707 WithS3IOOutputCount(float64(analyzeInfo.S3IOOutputCount)) 708 } 709 return 710 } 711 712 // GetInputRowsAndInputSize return plan.Node AnalyzeInfo InputRows and InputSize. 713 // migrate ExplainData.StatisticsRead to here 714 func GetInputRowsAndInputSize(ctx context.Context, node *plan.Node, options *ExplainOptions) (rows int64, size int64) { 715 if options.Analyze && node.AnalyzeInfo != nil { 716 return node.AnalyzeInfo.InputRows, node.AnalyzeInfo.InputSize 717 } 718 return 719 } 720 721 func (m MarshalNodeImpl) GetStatistics(ctx context.Context, options *ExplainOptions) Statistics { 722 statistics := NewStatistics() 723 if options.Analyze && m.node.AnalyzeInfo != nil { 724 analyzeInfo := m.node.AnalyzeInfo 725 times := []StatisticValue{ 726 { 727 Name: TimeConsumed, 728 Value: analyzeInfo.TimeConsumed, 729 Unit: Statistic_Unit_ns, 730 }, 731 { 732 Name: WaitTime, 733 Value: analyzeInfo.WaitTimeConsumed, 734 Unit: Statistic_Unit_ns, 735 }, 736 { 737 Name: ScanTime, 738 Value: analyzeInfo.ScanTime, 739 Unit: Statistic_Unit_ns, 740 }, 741 { 742 Name: InsertTime, 743 Value: analyzeInfo.InsertTime, 744 Unit: Statistic_Unit_ns, 745 }, 746 } 747 mbps := []StatisticValue{ 748 { 749 Name: InputRows, 750 Value: analyzeInfo.InputRows, 751 Unit: Statistic_Unit_count, //"count", 752 }, 753 { 754 Name: OutputRows, 755 Value: analyzeInfo.OutputRows, 756 Unit: Statistic_Unit_count, //"count", 757 }, 758 { 759 Name: InputSize, 760 Value: analyzeInfo.InputSize, 761 Unit: Statistic_Unit_byte, //"byte", 762 }, 763 { 764 Name: OutputSize, 765 Value: analyzeInfo.OutputSize, 766 Unit: Statistic_Unit_byte, //"byte", 767 }, 768 } 769 770 mems := []StatisticValue{ 771 { 772 Name: MemorySize, 773 Value: analyzeInfo.MemorySize, 774 Unit: Statistic_Unit_byte, //"byte", 775 }, 776 } 777 778 io := []StatisticValue{ 779 { 780 Name: DiskIO, 781 Value: analyzeInfo.DiskIO, 782 Unit: Statistic_Unit_byte, //"byte", 783 }, 784 { 785 Name: S3IOByte, 786 Value: analyzeInfo.S3IOByte, 787 Unit: Statistic_Unit_byte, //"byte", 788 }, 789 { 790 Name: S3IOInputCount, 791 Value: analyzeInfo.S3IOInputCount, 792 Unit: Statistic_Unit_count, //"count", 793 }, 794 { 795 Name: S3IOOutputCount, 796 Value: analyzeInfo.S3IOOutputCount, 797 Unit: Statistic_Unit_count, //"count", 798 }, 799 } 800 801 nw := []StatisticValue{ 802 { 803 Name: Network, 804 Value: analyzeInfo.NetworkIO, 805 Unit: Statistic_Unit_byte, //"byte", 806 }, 807 } 808 809 statistics.Time = append(statistics.Time, times...) 810 statistics.Throughput = append(statistics.Throughput, mbps...) 811 statistics.Memory = append(statistics.Memory, mems...) 812 statistics.IO = append(statistics.IO, io...) 813 statistics.Network = append(statistics.Network, nw...) 814 } 815 return *statistics 816 } 817 818 func (m MarshalNodeImpl) GetTotalStats() TotalStats { 819 totalStats := TotalStats{ 820 Name: "Time spent", 821 Unit: "ns", 822 } 823 if m.node.AnalyzeInfo != nil { 824 totalStats.Value = m.node.AnalyzeInfo.TimeConsumed 825 } else { 826 totalStats.Value = 0 827 } 828 return totalStats 829 } 830 831 var _ MarshalNode = MarshalNodeImpl{} 832 833 func GetExprsLabelValue(ctx context.Context, exprList []*plan.Expr, options *ExplainOptions) ([]string, error) { 834 if exprList == nil { 835 return make([]string, 0), nil 836 } 837 result := make([]string, 0, len(exprList)) 838 buf := bytes.NewBuffer(make([]byte, 0, 200)) 839 for _, v := range exprList { 840 buf.Reset() 841 err := describeExpr(ctx, v, options, buf) 842 if err != nil { 843 return result, err 844 } 845 result = append(result, buf.String()) 846 } 847 return result, nil 848 } 849 850 func GetOrderByLabelValue(ctx context.Context, orderbyList []*plan.OrderBySpec, options *ExplainOptions) ([]string, error) { 851 if orderbyList == nil { 852 return make([]string, 0), nil 853 } 854 result := make([]string, 0, len(orderbyList)) 855 buf := bytes.NewBuffer(make([]byte, 0, 200)) 856 for _, v := range orderbyList { 857 buf.Reset() 858 err := describeExpr(ctx, v.Expr, options, buf) 859 if err != nil { 860 return result, err 861 } 862 863 flagKey := int32(v.Flag) 864 orderbyFlag := plan.OrderBySpec_OrderByFlag_name[flagKey] 865 result = append(result, buf.String()+" "+orderbyFlag) 866 } 867 return result, nil 868 } 869 870 func GetDeleteTableLabelValue(deleteCtx *plan.DeleteCtx) []string { 871 if deleteCtx == nil { 872 return make([]string, 0) 873 } 874 result := make([]string, 0) 875 ref := deleteCtx.Ref 876 result = append(result, ref.SchemaName+"."+ref.ObjName) 877 return result 878 } 879 880 func GetTableColsLableValue(ctx context.Context, cols []*plan.ColDef, options *ExplainOptions) []string { 881 columns := make([]string, len(cols)) 882 for i, col := range cols { 883 columns[i] = col.Name 884 } 885 return columns 886 }