github.com/matrixorigin/matrixone@v0.7.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 "context" 19 "strconv" 20 "strings" 21 22 "github.com/matrixorigin/matrixone/pkg/common/moerr" 23 "github.com/matrixorigin/matrixone/pkg/pb/plan" 24 ) 25 26 func ConvertNode(ctx context.Context, node *plan.Node, options *ExplainOptions) (*Node, error) { 27 marshalNodeImpl := NewMarshalNodeImpl(node) 28 newNode := &Node{ 29 NodeId: strconv.FormatInt(int64(node.NodeId), 10), 30 Statistics: marshalNodeImpl.GetStatistics(ctx, options), 31 Stats: marshalNodeImpl.GetStats(), 32 TotalStats: marshalNodeImpl.GetTotalStats(), 33 } 34 name, err := marshalNodeImpl.GetNodeName(ctx) 35 if err != nil { 36 return nil, err 37 } 38 newNode.Name = name 39 40 title, err := marshalNodeImpl.GetNodeTitle(ctx, options) 41 if err != nil { 42 return nil, err 43 } 44 newNode.Title = title 45 46 labels, err := marshalNodeImpl.GetNodeLabels(ctx, options) 47 if err != nil { 48 return nil, err 49 } 50 newNode.Labels = labels 51 return newNode, nil 52 } 53 54 type MarshalNode interface { 55 GetNodeName(ctx context.Context) (string, error) 56 GetNodeTitle(ctx context.Context, options *ExplainOptions) (string, error) 57 GetNodeLabels(ctx context.Context, options *ExplainOptions) ([]Label, error) 58 GetStatistics(ctx context.Context, options *ExplainOptions) Statistics 59 GetStats() Stats 60 GetTotalStats() TotalStats 61 } 62 63 type MarshalNodeImpl struct { 64 node *plan.Node 65 } 66 67 func NewMarshalNodeImpl(node *plan.Node) *MarshalNodeImpl { 68 return &MarshalNodeImpl{ 69 node: node, 70 } 71 } 72 73 func (m MarshalNodeImpl) GetStats() Stats { 74 if m.node.Stats != nil { 75 return Stats{ 76 BlockNum: m.node.Stats.BlockNum, 77 Cost: m.node.Stats.Cost, 78 Outcnt: m.node.Stats.Outcnt, 79 HashmapSize: m.node.Stats.HashmapSize, 80 Rowsize: m.node.Stats.Rowsize, 81 } 82 } else { 83 return Stats{} 84 } 85 } 86 87 func (m MarshalNodeImpl) GetNodeName(ctx context.Context) (string, error) { 88 var name string 89 // Get the Node Name 90 switch m.node.NodeType { 91 case plan.Node_UNKNOWN: 92 name = "UnKnow Node" 93 case plan.Node_VALUE_SCAN: 94 name = "Values Scan" 95 case plan.Node_TABLE_SCAN: 96 name = "Table Scan" 97 case plan.Node_FUNCTION_SCAN: 98 name = "Function Scan" 99 case plan.Node_EXTERNAL_SCAN: 100 name = "External Scan" 101 case plan.Node_MATERIAL_SCAN: 102 name = "Material Scan" 103 case plan.Node_PROJECT: 104 name = "Project" 105 case plan.Node_EXTERNAL_FUNCTION: 106 name = "External Function" 107 case plan.Node_MATERIAL: 108 name = "Material" 109 case plan.Node_RECURSIVE_CTE: 110 name = "Recursive CTE" 111 case plan.Node_SINK: 112 name = "Sink" 113 case plan.Node_SINK_SCAN: 114 name = "Sink Scan" 115 case plan.Node_AGG: 116 name = "Aggregate" 117 case plan.Node_DISTINCT: 118 name = "Distinct" 119 case plan.Node_FILTER: 120 name = "Filter" 121 case plan.Node_JOIN: 122 name = "Join" 123 case plan.Node_SAMPLE: 124 name = "Sample" 125 case plan.Node_SORT: 126 name = "Sort" 127 case plan.Node_UNION: 128 name = "Union" 129 case plan.Node_UNION_ALL: 130 name = "Union All" 131 case plan.Node_UNIQUE: 132 name = "Unique" 133 case plan.Node_WINDOW: 134 name = "Window" 135 case plan.Node_BROADCAST: 136 name = "Broadcast" 137 case plan.Node_SPLIT: 138 name = "Split" 139 case plan.Node_GATHER: 140 name = "Gather" 141 case plan.Node_ASSERT: 142 name = "Assert" 143 case plan.Node_INSERT: 144 name = "Insert" 145 case plan.Node_UPDATE: 146 name = "Update" 147 case plan.Node_DELETE: 148 name = "Delete" 149 case plan.Node_INTERSECT: 150 name = "Intersect" 151 case plan.Node_INTERSECT_ALL: 152 name = "Intersect All" 153 case plan.Node_MINUS: 154 name = "Minus" 155 case plan.Node_MINUS_ALL: 156 name = "Minus All" 157 default: 158 return name, moerr.NewInternalError(ctx, "Unsupported node type when plan is serialized to json") 159 } 160 return name, nil 161 } 162 163 func (m MarshalNodeImpl) GetNodeTitle(ctx context.Context, options *ExplainOptions) (string, error) { 164 var result string 165 var err error 166 switch m.node.NodeType { 167 case plan.Node_TABLE_SCAN, plan.Node_EXTERNAL_SCAN, plan.Node_MATERIAL_SCAN, plan.Node_INSERT: 168 //"title" : "SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.DATE_DIM", 169 if m.node.ObjRef != nil { 170 result += m.node.ObjRef.GetSchemaName() + "." + m.node.ObjRef.GetObjName() 171 } else if m.node.TableDef != nil { 172 result += m.node.TableDef.GetName() 173 } else { 174 return result, moerr.NewInvalidInput(ctx, "Table definition not found when plan is serialized to json") 175 } 176 case plan.Node_UPDATE: 177 if m.node.UpdateCtx != nil { 178 first := true 179 for _, ctx := range m.node.UpdateCtx.Ref { 180 if !first { 181 result += ", " 182 } 183 result += ctx.SchemaName + "." + ctx.ObjName 184 if first { 185 first = false 186 } 187 } 188 } else { 189 return result, moerr.NewInvalidInput(ctx, "Table definition not found when plan is serialized to json") 190 } 191 case plan.Node_DELETE: 192 if m.node.DeleteCtx != nil { 193 first := true 194 for _, ctx := range m.node.DeleteCtx.Ref { 195 if !first { 196 result += ", " 197 } 198 result += ctx.SchemaName + "." + ctx.ObjName 199 if first { 200 first = false 201 } 202 } 203 } else { 204 return result, moerr.NewInternalError(ctx, "Table definition not found when plan is serialized to json") 205 } 206 case plan.Node_PROJECT, plan.Node_VALUE_SCAN, plan.Node_UNION, plan.Node_UNION_ALL, 207 plan.Node_INTERSECT, plan.Node_INTERSECT_ALL, plan.Node_MINUS: 208 //"title" : "STORE.S_STORE_NAME,STORE.S_STORE_ID,WSS.D_WEEK_SEQ" 209 exprs := NewExprListDescribeImpl(m.node.ProjectList) 210 result, err = exprs.GetDescription(ctx, options) 211 if err != nil { 212 return result, err 213 } 214 case plan.Node_AGG: 215 // "SUM(IFF(DATE_DIM.D_DAY_NAME = 'Sunday', STORE_SALES.SS_SALES_PRICE, null))" 216 exprs := NewExprListDescribeImpl(m.node.AggList) 217 result, err = exprs.GetDescription(ctx, options) 218 if err != nil { 219 return result, err 220 } 221 case plan.Node_FILTER: 222 //"title" : "(D_0.D_MONTH_SEQ >= 1189) AND (D_0.D_MONTH_SEQ <= 1200)", 223 exprs := NewExprListDescribeImpl(m.node.FilterList) 224 result, err = exprs.GetDescription(ctx, options) 225 if err != nil { 226 return result, err 227 } 228 case plan.Node_JOIN: 229 //"title" : "(DATE_DIM.D_DATE_SK = STORE_SALES.SS_SOLD_DATE_SK)", 230 exprs := NewExprListDescribeImpl(m.node.OnList) 231 result, err = exprs.GetDescription(ctx, options) 232 if err != nil { 233 return result, err 234 } 235 case plan.Node_SORT: 236 //"title" : "STORE.S_STORE_NAME ASC NULLS LAST,STORE.S_STORE_ID ASC NULLS LAST,WSS.D_WEEK_SEQ ASC NULLS LAST", 237 orderByDescImpl := NewOrderByDescribeImpl(m.node.OrderBy) 238 result, err = orderByDescImpl.GetDescription(ctx, options) 239 if err != nil { 240 return result, err 241 } 242 default: 243 return "", moerr.NewInternalError(ctx, "Unsupported node type when plan is serialized to json") 244 } 245 return strings.TrimSpace(result), nil 246 } 247 248 func (m MarshalNodeImpl) GetNodeLabels(ctx context.Context, options *ExplainOptions) ([]Label, error) { 249 labels := make([]Label, 0) 250 251 switch m.node.NodeType { 252 case plan.Node_TABLE_SCAN, plan.Node_FUNCTION_SCAN, plan.Node_EXTERNAL_SCAN, 253 plan.Node_MATERIAL_SCAN: 254 tableDef := m.node.TableDef 255 objRef := m.node.ObjRef 256 var fullTableName string 257 if objRef != nil { 258 fullTableName += objRef.GetSchemaName() + "." + objRef.GetObjName() 259 } else if tableDef != nil { 260 fullTableName += tableDef.GetName() 261 } else { 262 return nil, moerr.NewInternalError(ctx, "Table definition not found when plan is serialized to json") 263 } 264 265 labels = append(labels, Label{ 266 Name: "Full table name", 267 Value: fullTableName, 268 }) 269 270 // "name" : "Columns (2 / 28)", 271 columns := GetTableColsLableValue(ctx, tableDef.Cols, options) 272 273 labels = append(labels, Label{ 274 Name: "Columns", 275 Value: columns, 276 }) 277 278 labels = append(labels, Label{ 279 Name: "Total columns", 280 Value: len(tableDef.Name2ColIndex), 281 }) 282 283 labels = append(labels, Label{ 284 Name: "Scan columns", 285 Value: len(tableDef.Cols), 286 }) 287 288 case plan.Node_INSERT: 289 tableDef := m.node.TableDef 290 objRef := m.node.ObjRef 291 var fullTableName string 292 if objRef != nil { 293 fullTableName += objRef.GetSchemaName() + "." + objRef.GetObjName() 294 } else if tableDef != nil { 295 fullTableName += tableDef.GetName() 296 } else { 297 return nil, moerr.NewInternalError(ctx, "Table definition not found when plan is serialized to json") 298 } 299 300 labels = append(labels, Label{ 301 Name: "Full table name", 302 Value: fullTableName, 303 }) 304 305 // "name" : "Columns (2 / 28)", 306 columns := GetTableColsLableValue(ctx, tableDef.Cols, options) 307 308 labels = append(labels, Label{ 309 Name: "Columns", 310 Value: columns, 311 }) 312 313 labels = append(labels, Label{ 314 Name: "Total columns", 315 Value: len(tableDef.Cols), 316 }) 317 318 labels = append(labels, Label{ 319 Name: "Scan columns", 320 Value: len(tableDef.Cols), 321 }) 322 case plan.Node_UPDATE: 323 if m.node.UpdateCtx != nil { 324 updateTableNames := GetUpdateTableLableValue(ctx, m.node.UpdateCtx, options) 325 labels = append(labels, Label{ 326 Name: "Full table name", 327 Value: updateTableNames, 328 }) 329 330 updateCols := make([]string, 0) 331 for i, ctx := range m.node.UpdateCtx.Ref { 332 if m.node.UpdateCtx.UpdateCol[i] != nil { 333 upcols := GetUpdateTableColsLableValue(m.node.UpdateCtx.UpdateCol[i].Map, ctx.SchemaName, ctx.ObjName, options) 334 updateCols = append(updateCols, upcols...) 335 } 336 } 337 labels = append(labels, Label{ 338 Name: "Update columns", 339 Value: updateCols, 340 }) 341 } else { 342 return nil, moerr.NewInvalidInput(ctx, "Table definition not found when plan is serialized to json") 343 } 344 case plan.Node_DELETE: 345 if m.node.DeleteCtx != nil { 346 deleteTableNames := GetDeleteTableLableValue(ctx, m.node.DeleteCtx, options) 347 labels = append(labels, Label{ 348 Name: "Full table name", 349 Value: deleteTableNames, 350 }) 351 } else { 352 return nil, moerr.NewInvalidInput(ctx, "Table definition not found when plan is serialized to json") 353 } 354 case plan.Node_PROJECT: 355 value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options) 356 if err != nil { 357 return nil, err 358 } 359 labels = append(labels, Label{ 360 Name: "List of expressions", 361 Value: value, 362 }) 363 case plan.Node_AGG: 364 // Get Group key info 365 if len(m.node.GroupBy) > 0 { 366 // Get Grouping Key 367 value, err := GetExprsLabelValue(ctx, m.node.GroupBy, options) 368 if err != nil { 369 return nil, err 370 } 371 labels = append(labels, Label{ 372 Name: "Grouping keys", 373 Value: value, 374 }) 375 } 376 377 // Get Aggregate function info 378 if len(m.node.AggList) > 0 { 379 value, err := GetExprsLabelValue(ctx, m.node.AggList, options) 380 if err != nil { 381 return nil, err 382 } 383 labels = append(labels, Label{ 384 Name: "Aggregate functions", 385 Value: value, 386 }) 387 } 388 case plan.Node_FILTER: 389 value, err := GetExprsLabelValue(ctx, m.node.FilterList, options) 390 if err != nil { 391 return nil, err 392 } 393 labels = append(labels, Label{ 394 Name: "Filter conditions", 395 Value: value, 396 }) 397 case plan.Node_JOIN: 398 // Get Join type 399 labels = append(labels, Label{ 400 Name: "Join type", 401 Value: m.node.JoinType.String(), 402 }) 403 404 // Get Join Condition info 405 if len(m.node.OnList) > 0 { 406 value, err := GetExprsLabelValue(ctx, m.node.OnList, options) 407 if err != nil { 408 return nil, err 409 } 410 labels = append(labels, Label{ 411 Name: "Join conditions", 412 Value: value, 413 }) 414 } 415 labels = append(labels, Label{ 416 Name: "Left node id", 417 Value: m.node.Children[0], 418 }) 419 labels = append(labels, Label{ 420 Name: "Right node id", 421 Value: m.node.Children[1], 422 }) 423 case plan.Node_SORT: 424 result, err := GettOrderByLabelValue(ctx, m.node.OrderBy, options) 425 if err != nil { 426 return nil, err 427 } 428 labels = append(labels, Label{ 429 Name: "Sort keys", 430 Value: result, 431 }) 432 case plan.Node_VALUE_SCAN: 433 value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options) 434 if err != nil { 435 return nil, err 436 } 437 labels = append(labels, Label{ 438 Name: "List of values", 439 Value: value, 440 }) 441 case plan.Node_UNION: 442 value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options) 443 if err != nil { 444 return nil, err 445 } 446 labels = append(labels, Label{ 447 Name: "Union expressions", 448 Value: value, 449 }) 450 case plan.Node_UNION_ALL: 451 value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options) 452 if err != nil { 453 return nil, err 454 } 455 labels = append(labels, Label{ 456 Name: "Union all expressions", 457 Value: value, 458 }) 459 case plan.Node_INTERSECT: 460 value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options) 461 if err != nil { 462 return nil, err 463 } 464 labels = append(labels, Label{ 465 Name: "Intersect expressions", 466 Value: value, 467 }) 468 case plan.Node_INTERSECT_ALL: 469 value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options) 470 if err != nil { 471 return nil, err 472 } 473 labels = append(labels, Label{ 474 Name: "Intersect All expressions", 475 Value: value, 476 }) 477 case plan.Node_MINUS: 478 value, err := GetExprsLabelValue(ctx, m.node.ProjectList, options) 479 if err != nil { 480 return nil, err 481 } 482 labels = append(labels, Label{ 483 Name: "Minus expressions", 484 Value: value, 485 }) 486 default: 487 return nil, moerr.NewInternalError(ctx, "Unsupported node type when plan is serialized to json") 488 } 489 490 if m.node.NodeType != plan.Node_FILTER && m.node.FilterList != nil { 491 // Where condition 492 value, err := GetExprsLabelValue(ctx, m.node.FilterList, options) 493 if err != nil { 494 return nil, err 495 } 496 labels = append(labels, Label{ 497 Name: "Filter conditions", 498 Value: value, 499 }) 500 } 501 502 // Get Limit And Offset info 503 if m.node.Limit != nil { 504 limitInfo, err := describeExpr(ctx, m.node.Limit, options) 505 if err != nil { 506 return nil, err 507 } 508 labels = append(labels, Label{ 509 Name: "Number of rows", 510 Value: limitInfo, 511 }) 512 513 if m.node.Offset != nil { 514 offsetInfo, err := describeExpr(ctx, m.node.Offset, options) 515 if err != nil { 516 return nil, err 517 } 518 labels = append(labels, Label{ 519 Name: "Offset", 520 Value: offsetInfo, 521 }) 522 } else { 523 labels = append(labels, Label{ 524 Name: "Offset", 525 Value: 0, 526 }) 527 } 528 } 529 return labels, nil 530 } 531 532 const TimeConsumed = "Time Consumed" 533 const WaitTime = "Wait Time" 534 535 const InputRows = "Input Rows" 536 const OutputRows = "Output Rows" 537 const InputSize = "Input Size" 538 const OutputSize = "Output Size" 539 const MemorySize = "Memory Size" 540 const DiskIO = "Disk IO" 541 const S3IOByte = "S3 IO Byte" 542 const S3IOCount = "S3 IO Count" 543 const Network = "Network" 544 545 func (m MarshalNodeImpl) GetStatistics(ctx context.Context, options *ExplainOptions) Statistics { 546 statistics := NewStatistics() 547 if options.Analyze && m.node.AnalyzeInfo != nil { 548 analyzeInfo := m.node.AnalyzeInfo 549 times := []StatisticValue{ 550 { 551 Name: TimeConsumed, 552 Value: analyzeInfo.TimeConsumed, 553 Unit: "ns", 554 }, 555 { 556 Name: WaitTime, 557 Value: analyzeInfo.WaitTimeConsumed, 558 Unit: "ns", 559 }, 560 } 561 mbps := []StatisticValue{ 562 { 563 Name: InputRows, 564 Value: analyzeInfo.InputRows, 565 Unit: "count", 566 }, 567 { 568 Name: OutputRows, 569 Value: analyzeInfo.OutputRows, 570 Unit: "count", 571 }, 572 { 573 Name: InputSize, 574 Value: analyzeInfo.InputSize, 575 Unit: "byte", 576 }, 577 { 578 Name: OutputSize, 579 Value: analyzeInfo.OutputSize, 580 Unit: "byte", 581 }, 582 } 583 584 mems := []StatisticValue{ 585 { 586 Name: MemorySize, 587 Value: analyzeInfo.MemorySize, 588 Unit: "byte", 589 }, 590 } 591 592 io := []StatisticValue{ 593 { 594 Name: DiskIO, 595 Value: analyzeInfo.DiskIO, 596 Unit: "byte", 597 }, 598 { 599 Name: S3IOByte, 600 Value: analyzeInfo.S3IOByte, 601 Unit: "byte", 602 }, 603 { 604 Name: S3IOCount, 605 Value: analyzeInfo.S3IOCount, 606 Unit: "count", 607 }, 608 } 609 610 nw := []StatisticValue{ 611 { 612 Name: Network, 613 Value: analyzeInfo.NetworkIO, 614 Unit: "byte", 615 }, 616 } 617 618 statistics.Time = append(statistics.Time, times...) 619 statistics.Throughput = append(statistics.Throughput, mbps...) 620 statistics.Memory = append(statistics.Memory, mems...) 621 statistics.IO = append(statistics.IO, io...) 622 statistics.Network = append(statistics.Network, nw...) 623 } 624 return *statistics 625 } 626 627 func (m MarshalNodeImpl) GetTotalStats() TotalStats { 628 totalStats := TotalStats{ 629 Name: "Time spent", 630 Unit: "us", 631 } 632 if m.node.AnalyzeInfo != nil { 633 totalStats.Value = m.node.AnalyzeInfo.TimeConsumed 634 } else { 635 totalStats.Value = 0 636 } 637 return totalStats 638 } 639 640 var _ MarshalNode = MarshalNodeImpl{} 641 642 func GetExprsLabelValue(ctx context.Context, exprList []*plan.Expr, options *ExplainOptions) ([]string, error) { 643 if exprList == nil { 644 return make([]string, 0), nil 645 } 646 result := make([]string, 0) 647 for _, v := range exprList { 648 descV, err := describeExpr(ctx, v, options) 649 if err != nil { 650 return result, err 651 } 652 result = append(result, descV) 653 } 654 return result, nil 655 } 656 657 func GettOrderByLabelValue(ctx context.Context, orderbyList []*plan.OrderBySpec, options *ExplainOptions) ([]string, error) { 658 if orderbyList == nil { 659 return make([]string, 0), nil 660 } 661 result := make([]string, 0) 662 for _, v := range orderbyList { 663 descExpr, err := describeExpr(ctx, v.Expr, options) 664 if err != nil { 665 return result, err 666 } 667 668 flagKey := int32(v.Flag) 669 orderbyFlag := plan.OrderBySpec_OrderByFlag_name[flagKey] 670 result = append(result, descExpr+" "+orderbyFlag) 671 } 672 return result, nil 673 } 674 675 func GetDeleteTableLableValue(ctx context.Context, deleteCtx *plan.DeleteCtx, options *ExplainOptions) []string { 676 if deleteCtx == nil { 677 return make([]string, 0) 678 } 679 result := make([]string, 0) 680 for _, ctx := range deleteCtx.Ref { 681 result = append(result, ctx.SchemaName+"."+ctx.ObjName) 682 } 683 return result 684 } 685 686 func GetUpdateTableLableValue(ctx context.Context, updateCtx *plan.UpdateCtx, options *ExplainOptions) []string { 687 if updateCtx == nil { 688 return make([]string, 0) 689 } 690 result := make([]string, 0) 691 for _, ctx := range updateCtx.Ref { 692 result = append(result, ctx.SchemaName+"."+ctx.ObjName) 693 } 694 return result 695 } 696 697 func GetTableColsLableValue(ctx context.Context, cols []*plan.ColDef, options *ExplainOptions) []string { 698 columns := make([]string, len(cols)) 699 for i, col := range cols { 700 columns[i] = col.Name 701 } 702 return columns 703 } 704 705 func GetUpdateTableColsLableValue(cols map[string]int32, db string, tname string, options *ExplainOptions) []string { 706 columns := make([]string, len(cols)) 707 i := 0 708 for col := range cols { 709 columns[i] = db + "." + tname + "." + col 710 i++ 711 } 712 return columns 713 }