github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/explain/explain_node.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 "sort" 22 "strconv" 23 24 plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" 25 26 "github.com/matrixorigin/matrixone/pkg/common/moerr" 27 "github.com/matrixorigin/matrixone/pkg/pb/plan" 28 ) 29 30 var _ NodeDescribe = &NodeDescribeImpl{} 31 32 const MB = 1024 * 1024 33 const GB = MB * 1024 34 const MILLION = 1000000 35 36 type NodeDescribeImpl struct { 37 Node *plan.Node 38 } 39 40 func NewNodeDescriptionImpl(node *plan.Node) *NodeDescribeImpl { 41 return &NodeDescribeImpl{ 42 Node: node, 43 } 44 } 45 46 const TableScan = "Table Scan" 47 const ExternalScan = "External Scan" 48 49 func (ndesc *NodeDescribeImpl) GetNodeBasicInfo(ctx context.Context, options *ExplainOptions) (string, error) { 50 buf := bytes.NewBuffer(make([]byte, 0, 400)) 51 var pname string /* node type name for text output */ 52 53 // Get the Node Name 54 switch ndesc.Node.NodeType { 55 case plan.Node_UNKNOWN: 56 pname = "UnKnow Node" 57 case plan.Node_VALUE_SCAN: 58 pname = "Values Scan" 59 case plan.Node_TABLE_SCAN: 60 pname = TableScan 61 case plan.Node_EXTERNAL_SCAN: 62 pname = ExternalScan 63 case plan.Node_SOURCE_SCAN: 64 pname = "Source Scan" 65 case plan.Node_MATERIAL_SCAN: 66 pname = "Material Scan" 67 case plan.Node_PROJECT: 68 pname = "Project" 69 case plan.Node_EXTERNAL_FUNCTION: 70 pname = "External Function" 71 case plan.Node_MATERIAL: 72 pname = "Material" 73 case plan.Node_SINK: 74 pname = "Sink" 75 case plan.Node_SINK_SCAN: 76 pname = "Sink Scan" 77 case plan.Node_RECURSIVE_SCAN: 78 pname = "Recursive Scan" 79 case plan.Node_RECURSIVE_CTE: 80 pname = "CTE Scan" 81 case plan.Node_AGG: 82 pname = "Aggregate" 83 case plan.Node_DISTINCT: 84 pname = "Distinct" 85 case plan.Node_FILTER: 86 pname = "Filter" 87 case plan.Node_JOIN: 88 pname = "Join" 89 case plan.Node_SAMPLE: 90 pname = "Sample" 91 case plan.Node_SORT: 92 pname = "Sort" 93 case plan.Node_PARTITION: 94 pname = "Partition" 95 case plan.Node_UNION: 96 pname = "Union" 97 case plan.Node_UNION_ALL: 98 pname = "Union All" 99 case plan.Node_UNIQUE: 100 pname = "Unique" 101 case plan.Node_WINDOW: 102 pname = "Window" 103 case plan.Node_TIME_WINDOW: 104 pname = "Time window" 105 case plan.Node_FILL: 106 pname = "Fill" 107 case plan.Node_BROADCAST: 108 pname = "Broadcast" 109 case plan.Node_SPLIT: 110 pname = "Split" 111 case plan.Node_GATHER: 112 pname = "Gather" 113 case plan.Node_ASSERT: 114 pname = "Assert" 115 case plan.Node_INSERT: 116 pname = "Insert" 117 case plan.Node_DELETE: 118 pname = "Delete" 119 case plan.Node_INTERSECT: 120 pname = "Intersect" 121 case plan.Node_INTERSECT_ALL: 122 pname = "Intersect All" 123 case plan.Node_MINUS: 124 pname = "Minus" 125 case plan.Node_MINUS_ALL: 126 pname = "Minus All" 127 case plan.Node_FUNCTION_SCAN: 128 pname = "Table Function" 129 case plan.Node_PRE_INSERT: 130 pname = "PreInsert" 131 case plan.Node_PRE_INSERT_UK: 132 pname = "PreInsert UniqueKey" 133 case plan.Node_PRE_INSERT_SK: 134 pname = "PreInsert SecondaryKey" 135 case plan.Node_PRE_DELETE: 136 pname = "PreDelete" 137 case plan.Node_ON_DUPLICATE_KEY: 138 pname = "On Duplicate Key" 139 case plan.Node_FUZZY_FILTER: 140 pname = "Fuzzy Filter for duplicate key" 141 case plan.Node_LOCK_OP: 142 pname = "Lock" 143 default: 144 panic("error node type") 145 } 146 147 // Get Node's operator object info ,such as table, view 148 if options.Format == EXPLAIN_FORMAT_TEXT { 149 buf.WriteString(pname) 150 switch ndesc.Node.NodeType { 151 case plan.Node_VALUE_SCAN: 152 buf.WriteString(" \"*VALUES*\" ") 153 case plan.Node_TABLE_SCAN, plan.Node_EXTERNAL_SCAN, plan.Node_MATERIAL_SCAN, plan.Node_INSERT, plan.Node_SOURCE_SCAN: 154 buf.WriteString(" on ") 155 if ndesc.Node.ObjRef != nil { 156 buf.WriteString(ndesc.Node.ObjRef.GetSchemaName() + "." + ndesc.Node.ObjRef.GetObjName()) 157 } else if ndesc.Node.TableDef != nil { 158 buf.WriteString(ndesc.Node.TableDef.GetName()) 159 } 160 if ndesc.Node.Stats.ForceOneCN { 161 buf.WriteString(" [ForceOneCN]") 162 } 163 case plan.Node_FUNCTION_SCAN: 164 buf.WriteString(" on ") 165 if ndesc.Node.TableDef != nil && ndesc.Node.TableDef.TblFunc != nil { 166 buf.WriteString(ndesc.Node.TableDef.TblFunc.Name) 167 } 168 case plan.Node_DELETE: 169 buf.WriteString(" on ") 170 if ndesc.Node.DeleteCtx != nil { 171 ctx := ndesc.Node.DeleteCtx.Ref 172 buf.WriteString(ctx.SchemaName + "." + ctx.ObjName) 173 } 174 case plan.Node_PRE_INSERT: 175 buf.WriteString(" on ") 176 if ndesc.Node.PreInsertCtx != nil { 177 if ndesc.Node.PreInsertCtx.Ref != nil { 178 buf.WriteString(ndesc.Node.PreInsertCtx.Ref.GetSchemaName() + "." + ndesc.Node.PreInsertCtx.Ref.GetObjName()) 179 } else if ndesc.Node.PreInsertCtx.TableDef != nil { 180 buf.WriteString(ndesc.Node.TableDef.GetName()) 181 } 182 } 183 case plan.Node_PRE_DELETE: 184 buf.WriteString(" on ") 185 if ndesc.Node.ObjRef != nil { 186 buf.WriteString(ndesc.Node.ObjRef.GetSchemaName() + "." + ndesc.Node.ObjRef.GetObjName()) 187 } else if ndesc.Node.TableDef != nil { 188 buf.WriteString(ndesc.Node.TableDef.GetName()) 189 } 190 } 191 } 192 193 // Get Costs info of Node 194 if options.Format == EXPLAIN_FORMAT_TEXT { 195 //result += " (cost=%.2f..%.2f rows=%.0f width=%f)" 196 if options.Verbose { 197 costDescImpl := &CostDescribeImpl{ 198 Stats: ndesc.Node.GetStats(), 199 } 200 err := costDescImpl.GetDescription(ctx, options, buf) 201 if err != nil { 202 return "", err 203 } 204 } 205 } else if options.Format == EXPLAIN_FORMAT_JSON { 206 return "", moerr.NewNYI(ctx, "explain format json") 207 } else if options.Format == EXPLAIN_FORMAT_DOT { 208 return "", moerr.NewNYI(ctx, "explain format dot") 209 } 210 return buf.String(), nil 211 } 212 213 func (ndesc *NodeDescribeImpl) GetActualAnalyzeInfo(ctx context.Context, options *ExplainOptions) (string, error) { 214 buf := bytes.NewBuffer(make([]byte, 0, 400)) 215 buf.WriteString("Analyze: ") 216 if ndesc.Node.AnalyzeInfo != nil { 217 impl := NewAnalyzeInfoDescribeImpl(ndesc.Node.AnalyzeInfo) 218 options.NodeType = ndesc.Node.NodeType 219 err := impl.GetDescription(ctx, options, buf) 220 if err != nil { 221 return "", err 222 } 223 } else { 224 buf.WriteString("timeConsumed=0ns waitTime=0ns inputRows=0 outputRows=0 inputSize=0 bytes outputSize:0 bytes, memorySize=0 bytes") 225 } 226 return buf.String(), nil 227 } 228 229 func (ndesc *NodeDescribeImpl) GetTableDef(ctx context.Context, options *ExplainOptions) (string, error) { 230 result := "Table: " 231 if ndesc.Node.NodeType == plan.Node_TABLE_SCAN { 232 tableDef := ndesc.Node.TableDef 233 result += "'" + tableDef.Name + "' (" 234 first := true 235 for i, col := range tableDef.Cols { 236 if !first { 237 result += ", " 238 } 239 first = false 240 result += strconv.Itoa(i) + ":'" + col.Name + "'" 241 } 242 result += ")" 243 } else { 244 panic("implement me") 245 } 246 return result, nil 247 } 248 249 func (ndesc *NodeDescribeImpl) GetExtraInfo(ctx context.Context, options *ExplainOptions) ([]string, error) { 250 lines := make([]string, 0) 251 252 // Get partition prune information 253 if ndesc.Node.NodeType == plan.Node_TABLE_SCAN && ndesc.Node.TableDef.Partition != nil { 254 partPruneInfo, err := ndesc.GetPartitionPruneInfo(ctx, options) 255 if err != nil { 256 return nil, err 257 } 258 lines = append(lines, partPruneInfo) 259 } 260 261 // Get Sort list info 262 if len(ndesc.Node.OrderBy) > 0 { 263 orderByInfo, err := ndesc.GetOrderByInfo(ctx, options) 264 if err != nil { 265 return nil, err 266 } 267 lines = append(lines, orderByInfo) 268 } 269 270 // Get Join type info 271 if ndesc.Node.NodeType == plan.Node_JOIN { 272 joinTypeInfo, err := ndesc.GetJoinTypeInfo(ctx, options) 273 if err != nil { 274 return nil, err 275 } 276 lines = append(lines, joinTypeInfo) 277 } 278 279 // Get Join Condition info 280 if len(ndesc.Node.OnList) > 0 { 281 joinOnInfo, err := ndesc.GetJoinConditionInfo(ctx, options) 282 if err != nil { 283 return nil, err 284 } 285 lines = append(lines, joinOnInfo) 286 } 287 288 // Get Group key info 289 if len(ndesc.Node.GroupBy) > 0 { 290 groupByInfo, err := ndesc.GetGroupByInfo(ctx, options) 291 if err != nil { 292 return nil, err 293 } 294 lines = append(lines, groupByInfo) 295 } 296 297 if ndesc.Node.NodeType == plan.Node_FILL { 298 fillCoslInfo, err := ndesc.GetFillColsInfo(ctx, options) 299 if err != nil { 300 return nil, err 301 } 302 lines = append(lines, fillCoslInfo) 303 fillModelInfo, err := ndesc.GetFillModeInfo(ctx, options) 304 if err != nil { 305 return nil, err 306 } 307 lines = append(lines, fillModelInfo) 308 } 309 310 // Get Aggregate function info 311 if len(ndesc.Node.AggList) > 0 && ndesc.Node.NodeType != plan.Node_FILL { 312 var listInfo string 313 var err error 314 if ndesc.Node.NodeType == plan.Node_SAMPLE { 315 listInfo, err = ndesc.GetSampleFuncInfo(ctx, options) 316 } else { 317 listInfo, err = ndesc.GetAggregationInfo(ctx, options) 318 } 319 if err != nil { 320 return nil, err 321 } 322 lines = append(lines, listInfo) 323 } 324 325 // Get Window function info 326 if ndesc.Node.NodeType == plan.Node_WINDOW { 327 windowSpecListInfo, err := ndesc.GetWindowSpectListInfo(ctx, options) 328 if err != nil { 329 return nil, err 330 } 331 lines = append(lines, windowSpecListInfo) 332 } 333 334 // Get Filter list info 335 if len(ndesc.Node.FilterList) > 0 { 336 filterInfo, err := ndesc.GetFilterConditionInfo(ctx, options) 337 if err != nil { 338 return nil, err 339 } 340 lines = append(lines, filterInfo) 341 } 342 343 // Get Block Filter list info 344 if len(ndesc.Node.BlockFilterList) > 0 { 345 filterInfo, err := ndesc.GetBlockFilterConditionInfo(ctx, options) 346 if err != nil { 347 return nil, err 348 } 349 lines = append(lines, filterInfo) 350 } 351 352 if len(ndesc.Node.RuntimeFilterProbeList) > 0 { 353 filterInfo, err := ndesc.GetRuntimeFilteProbeInfo(ctx, options) 354 if err != nil { 355 return nil, err 356 } 357 lines = append(lines, filterInfo) 358 } 359 360 if len(ndesc.Node.RuntimeFilterBuildList) > 0 { 361 filterInfo, err := ndesc.GetRuntimeFilterBuildInfo(ctx, options) 362 if err != nil { 363 return nil, err 364 } 365 lines = append(lines, filterInfo) 366 } 367 368 // Get Limit And Offset info 369 if ndesc.Node.Limit != nil { 370 buf := bytes.NewBuffer(make([]byte, 0, 160)) 371 buf.WriteString("Limit: ") 372 err := describeExpr(ctx, ndesc.Node.Limit, options, buf) 373 if err != nil { 374 return nil, err 375 } 376 if ndesc.Node.Offset != nil { 377 buf.WriteString(", Offset: ") 378 err := describeExpr(ctx, ndesc.Node.Offset, options, buf) 379 if err != nil { 380 return nil, err 381 } 382 } 383 lines = append(lines, buf.String()) 384 } 385 386 //if ndesc.Node.UpdateList != nil { 387 // updateListDesc := &UpdateListDescribeImpl{ 388 // UpdateList: ndesc.Node.UpdateList, 389 // } 390 // updatedesc, err := updateListDesc.GetDescription(options) 391 // if err != nil { 392 // return nil, err 393 // } 394 // lines = append(lines, "Set columns with("+updatedesc+")") 395 //} 396 397 if len(ndesc.Node.SendMsgList) > 0 { 398 msgInfo, err := ndesc.GetSendMessageInfo(ctx, options) 399 if err != nil { 400 return nil, err 401 } 402 lines = append(lines, msgInfo) 403 } 404 405 if len(ndesc.Node.RecvMsgList) > 0 { 406 msgInfo, err := ndesc.GetRecvMessageInfo(ctx, options) 407 if err != nil { 408 return nil, err 409 } 410 lines = append(lines, msgInfo) 411 } 412 return lines, nil 413 } 414 415 func (ndesc *NodeDescribeImpl) GetProjectListInfo(ctx context.Context, options *ExplainOptions) (string, error) { 416 buf := bytes.NewBuffer(make([]byte, 0, 400)) 417 buf.WriteString("Output: ") 418 exprs := NewExprListDescribeImpl(ndesc.Node.ProjectList) 419 err := exprs.GetDescription(ctx, options, buf) 420 if err != nil { 421 return "", err 422 } 423 return buf.String(), nil 424 } 425 426 func (ndesc *NodeDescribeImpl) GetJoinTypeInfo(ctx context.Context, options *ExplainOptions) (string, error) { 427 result := "Join Type: " + ndesc.Node.JoinType.String() 428 if ndesc.Node.BuildOnLeft { 429 if ndesc.Node.JoinType == plan.Node_SEMI || ndesc.Node.JoinType == plan.Node_ANTI { 430 result = "Join Type: RIGHT " + ndesc.Node.JoinType.String() 431 } 432 } 433 if ndesc.Node.Stats.HashmapStats != nil && ndesc.Node.Stats.HashmapStats.HashOnPK { 434 result += " hashOnPK" 435 } 436 return result, nil 437 } 438 439 func (ndesc *NodeDescribeImpl) GetJoinConditionInfo(ctx context.Context, options *ExplainOptions) (string, error) { 440 buf := bytes.NewBuffer(make([]byte, 0, 300)) 441 buf.WriteString("Join Cond: ") 442 exprs := NewExprListDescribeImpl(ndesc.Node.OnList) 443 err := exprs.GetDescription(ctx, options, buf) 444 if err != nil { 445 return "", err 446 } 447 448 if ndesc.Node.Stats.HashmapStats.Shuffle { 449 idx := ndesc.Node.Stats.HashmapStats.ShuffleColIdx 450 shuffleType := ndesc.Node.Stats.HashmapStats.ShuffleType 451 var hashCol *plan.Expr 452 switch exprImpl := ndesc.Node.OnList[idx].Expr.(type) { 453 case *plan.Expr_F: 454 hashCol = exprImpl.F.Args[0] 455 } 456 457 if shuffleType == plan.ShuffleType_Hash { 458 buf.WriteString(" shuffle: hash(") 459 err := describeExpr(ctx, hashCol, options, buf) 460 if err != nil { 461 return "", err 462 } 463 buf.WriteString(")") 464 } else { 465 buf.WriteString(" shuffle: range(") 466 err := describeExpr(ctx, hashCol, options, buf) 467 if err != nil { 468 return "", err 469 } 470 buf.WriteString(")") 471 } 472 473 if ndesc.Node.Stats.HashmapStats.ShuffleTypeForMultiCN == plan.ShuffleTypeForMultiCN_Hybrid { 474 buf.WriteString(" HYBRID ") 475 } 476 } 477 478 return buf.String(), nil 479 } 480 481 func (ndesc *NodeDescribeImpl) GetPartitionPruneInfo(ctx context.Context, options *ExplainOptions) (string, error) { 482 buf := bytes.NewBuffer(make([]byte, 0, 300)) 483 buf.WriteString("Hit Partition: ") 484 if options.Format == EXPLAIN_FORMAT_TEXT { 485 if ndesc.Node.PartitionPrune != nil { 486 first := true 487 for _, v := range ndesc.Node.PartitionPrune.SelectedPartitions { 488 if !first { 489 buf.WriteString(", ") 490 } 491 first = false 492 buf.WriteString(v.PartitionName) 493 } 494 } else { 495 buf.WriteString("all partitions") 496 } 497 } else if options.Format == EXPLAIN_FORMAT_JSON { 498 return "", moerr.NewNYI(ctx, "explain format json") 499 } else if options.Format == EXPLAIN_FORMAT_DOT { 500 return "", moerr.NewNYI(ctx, "explain format dot") 501 } 502 return buf.String(), nil 503 } 504 505 func (ndesc *NodeDescribeImpl) GetFilterConditionInfo(ctx context.Context, options *ExplainOptions) (string, error) { 506 buf := bytes.NewBuffer(make([]byte, 0, 512)) 507 buf.WriteString("Filter Cond: ") 508 if options.Format == EXPLAIN_FORMAT_TEXT { 509 first := true 510 for _, v := range ndesc.Node.FilterList { 511 if !first { 512 buf.WriteString(", ") 513 } 514 first = false 515 err := describeExpr(ctx, v, options, buf) 516 if err != nil { 517 return "", err 518 } 519 } 520 } else if options.Format == EXPLAIN_FORMAT_JSON { 521 return "", moerr.NewNYI(ctx, "explain format json") 522 } else if options.Format == EXPLAIN_FORMAT_DOT { 523 return "", moerr.NewNYI(ctx, "explain format dot") 524 } 525 return buf.String(), nil 526 } 527 528 func (ndesc *NodeDescribeImpl) GetBlockFilterConditionInfo(ctx context.Context, options *ExplainOptions) (string, error) { 529 buf := bytes.NewBuffer(make([]byte, 0, 300)) 530 buf.WriteString("Block Filter Cond: ") 531 if options.Format == EXPLAIN_FORMAT_TEXT { 532 first := true 533 for _, v := range ndesc.Node.BlockFilterList { 534 if !first { 535 buf.WriteString(", ") 536 } 537 first = false 538 err := describeExpr(ctx, v, options, buf) 539 if err != nil { 540 return "", err 541 } 542 } 543 } else if options.Format == EXPLAIN_FORMAT_JSON { 544 return "", moerr.NewNYI(ctx, "explain format json") 545 } else if options.Format == EXPLAIN_FORMAT_DOT { 546 return "", moerr.NewNYI(ctx, "explain format dot") 547 } 548 return buf.String(), nil 549 } 550 551 func (ndesc *NodeDescribeImpl) GetRuntimeFilteProbeInfo(ctx context.Context, options *ExplainOptions) (string, error) { 552 buf := bytes.NewBuffer(make([]byte, 0, 300)) 553 buf.WriteString("Runtime Filter Probe: ") 554 if options.Format == EXPLAIN_FORMAT_TEXT { 555 first := true 556 for _, v := range ndesc.Node.RuntimeFilterProbeList { 557 if !first { 558 buf.WriteString(", ") 559 } 560 first = false 561 err := describeExpr(ctx, v.Expr, options, buf) 562 if err != nil { 563 return "", err 564 } 565 if v.MatchPrefix { 566 buf.WriteString(" Match Prefix") 567 } 568 } 569 } else if options.Format == EXPLAIN_FORMAT_JSON { 570 return "", moerr.NewNYI(ctx, "explain format json") 571 } else if options.Format == EXPLAIN_FORMAT_DOT { 572 return "", moerr.NewNYI(ctx, "explain format dot") 573 } 574 return buf.String(), nil 575 } 576 577 func (ndesc *NodeDescribeImpl) GetRuntimeFilterBuildInfo(ctx context.Context, options *ExplainOptions) (string, error) { 578 buf := bytes.NewBuffer(make([]byte, 0, 300)) 579 buf.WriteString("Runtime Filter Build: ") 580 if options.Format == EXPLAIN_FORMAT_TEXT { 581 first := true 582 for _, v := range ndesc.Node.RuntimeFilterBuildList { 583 if !first { 584 buf.WriteString(", ") 585 } 586 first = false 587 err := describeExpr(ctx, v.Expr, options, buf) 588 if err != nil { 589 return "", err 590 } 591 } 592 } else if options.Format == EXPLAIN_FORMAT_JSON { 593 return "", moerr.NewNYI(ctx, "explain format json") 594 } else if options.Format == EXPLAIN_FORMAT_DOT { 595 return "", moerr.NewNYI(ctx, "explain format dot") 596 } 597 return buf.String(), nil 598 } 599 600 func (ndesc *NodeDescribeImpl) GetSendMessageInfo(ctx context.Context, options *ExplainOptions) (string, error) { 601 buf := bytes.NewBuffer(make([]byte, 0, 300)) 602 buf.WriteString("Send Message: ") 603 if options.Format == EXPLAIN_FORMAT_TEXT { 604 first := true 605 for _, v := range ndesc.Node.SendMsgList { 606 if !first { 607 buf.WriteString(", ") 608 } 609 first = false 610 describeMessage(v, buf) 611 } 612 } else if options.Format == EXPLAIN_FORMAT_JSON { 613 return "", moerr.NewNYI(ctx, "explain format json") 614 } else if options.Format == EXPLAIN_FORMAT_DOT { 615 return "", moerr.NewNYI(ctx, "explain format dot") 616 } 617 return buf.String(), nil 618 } 619 620 func (ndesc *NodeDescribeImpl) GetRecvMessageInfo(ctx context.Context, options *ExplainOptions) (string, error) { 621 buf := bytes.NewBuffer(make([]byte, 0, 300)) 622 buf.WriteString("Recv Message: ") 623 if options.Format == EXPLAIN_FORMAT_TEXT { 624 first := true 625 for _, v := range ndesc.Node.RecvMsgList { 626 if !first { 627 buf.WriteString(", ") 628 } 629 first = false 630 describeMessage(v, buf) 631 } 632 } else if options.Format == EXPLAIN_FORMAT_JSON { 633 return "", moerr.NewNYI(ctx, "explain format json") 634 } else if options.Format == EXPLAIN_FORMAT_DOT { 635 return "", moerr.NewNYI(ctx, "explain format dot") 636 } 637 return buf.String(), nil 638 } 639 640 func (ndesc *NodeDescribeImpl) GetGroupByInfo(ctx context.Context, options *ExplainOptions) (string, error) { 641 buf := bytes.NewBuffer(make([]byte, 0, 300)) 642 buf.WriteString("Group Key: ") 643 if options.Format == EXPLAIN_FORMAT_TEXT { 644 first := true 645 for _, v := range ndesc.Node.GetGroupBy() { 646 if !first { 647 buf.WriteString(", ") 648 } 649 first = false 650 err := describeExpr(ctx, v, options, buf) 651 if err != nil { 652 return "", err 653 } 654 } 655 } else if options.Format == EXPLAIN_FORMAT_JSON { 656 return "", moerr.NewNYI(ctx, "explain format json") 657 } else if options.Format == EXPLAIN_FORMAT_DOT { 658 return "", moerr.NewNYI(ctx, "explain format dot") 659 } 660 661 if ndesc.Node.Stats.HashmapStats != nil && ndesc.Node.Stats.HashmapStats.Shuffle { 662 idx := ndesc.Node.Stats.HashmapStats.ShuffleColIdx 663 shuffleType := ndesc.Node.Stats.HashmapStats.ShuffleType 664 if ndesc.Node.Stats.HashmapStats.ShuffleMethod != plan.ShuffleMethod_Reuse { 665 if shuffleType == plan.ShuffleType_Hash { 666 buf.WriteString(" shuffle: hash(") 667 err := describeExpr(ctx, ndesc.Node.GroupBy[idx], options, buf) 668 if err != nil { 669 return "", err 670 } 671 buf.WriteString(")") 672 } else { 673 buf.WriteString(" shuffle: range(") 674 err := describeExpr(ctx, ndesc.Node.GroupBy[idx], options, buf) 675 if err != nil { 676 return "", err 677 } 678 buf.WriteString(")") 679 } 680 } 681 682 if ndesc.Node.Stats.HashmapStats.ShuffleMethod == plan.ShuffleMethod_Reuse { 683 buf.WriteString(" shuffle: REUSE ") 684 } else if ndesc.Node.Stats.HashmapStats.ShuffleMethod == plan.ShuffleMethod_Reshuffle { 685 buf.WriteString(" RESHUFFLE ") 686 } 687 } 688 return buf.String(), nil 689 } 690 691 func (ndesc *NodeDescribeImpl) GetAggregationInfo(ctx context.Context, options *ExplainOptions) (string, error) { 692 buf := bytes.NewBuffer(make([]byte, 0, 300)) 693 buf.WriteString("Aggregate Functions: ") 694 if options.Format == EXPLAIN_FORMAT_TEXT { 695 first := true 696 for _, v := range ndesc.Node.GetAggList() { 697 if !first { 698 buf.WriteString(", ") 699 } 700 first = false 701 err := describeExpr(ctx, v, options, buf) 702 if err != nil { 703 return "", err 704 } 705 } 706 } else if options.Format == EXPLAIN_FORMAT_JSON { 707 return "", moerr.NewNYI(ctx, "explain format json") 708 } else if options.Format == EXPLAIN_FORMAT_DOT { 709 return "", moerr.NewNYI(ctx, "explain format dot") 710 } 711 return buf.String(), nil 712 } 713 714 func (ndesc *NodeDescribeImpl) GetSampleFuncInfo(ctx context.Context, options *ExplainOptions) (string, error) { 715 buf := bytes.NewBuffer(make([]byte, 0, 300)) 716 if ndesc.Node.SampleFunc.Rows == plan2.NotSampleByRows { 717 buf.WriteString(fmt.Sprintf("Sample %.2f Percent by: ", ndesc.Node.SampleFunc.Percent)) 718 } else { 719 buf.WriteString(fmt.Sprintf("Sample %d Rows by: ", ndesc.Node.SampleFunc.Rows)) 720 } 721 722 if options.Format == EXPLAIN_FORMAT_TEXT { 723 first := true 724 for _, v := range ndesc.Node.GetAggList() { 725 if !first { 726 buf.WriteString(", ") 727 } 728 first = false 729 err := describeExpr(ctx, v, options, buf) 730 if err != nil { 731 return "", err 732 } 733 } 734 } else if options.Format == EXPLAIN_FORMAT_JSON { 735 return "", moerr.NewNYI(ctx, "explain format json") 736 } else if options.Format == EXPLAIN_FORMAT_DOT { 737 return "", moerr.NewNYI(ctx, "explain format dot") 738 } 739 return buf.String(), nil 740 } 741 742 func (ndesc *NodeDescribeImpl) GetFillColsInfo(ctx context.Context, options *ExplainOptions) (string, error) { 743 buf := bytes.NewBuffer(make([]byte, 0, 300)) 744 buf.WriteString("Fill Columns: ") 745 if options.Format == EXPLAIN_FORMAT_TEXT { 746 first := true 747 for _, v := range ndesc.Node.GetAggList() { 748 if !first { 749 buf.WriteString(", ") 750 } 751 first = false 752 err := describeExpr(ctx, v, options, buf) 753 if err != nil { 754 return "", err 755 } 756 } 757 } else if options.Format == EXPLAIN_FORMAT_JSON { 758 return "", moerr.NewNYI(ctx, "explain format json") 759 } else if options.Format == EXPLAIN_FORMAT_DOT { 760 return "", moerr.NewNYI(ctx, "explain format dot") 761 } 762 return buf.String(), nil 763 } 764 765 func (ndesc *NodeDescribeImpl) GetFillModeInfo(ctx context.Context, options *ExplainOptions) (string, error) { 766 buf := bytes.NewBuffer(make([]byte, 0, 300)) 767 buf.WriteString("Fill Mode: ") 768 if options.Format == EXPLAIN_FORMAT_TEXT { 769 switch ndesc.Node.FillType { 770 case plan.Node_NONE: 771 buf.WriteString("None") 772 case plan.Node_LINEAR: 773 buf.WriteString("Linear") 774 case plan.Node_NULL: 775 buf.WriteString("Null") 776 case plan.Node_VALUE: 777 buf.WriteString("Value") 778 case plan.Node_PREV: 779 buf.WriteString("Prev") 780 case plan.Node_NEXT: 781 buf.WriteString("Next") 782 } 783 if len(ndesc.Node.FillVal) > 0 { 784 buf.WriteString(" Fill Value: ") 785 first := true 786 for _, v := range ndesc.Node.GetFillVal() { 787 if !first { 788 buf.WriteString(", ") 789 } 790 first = false 791 err := describeExpr(ctx, v, options, buf) 792 if err != nil { 793 return "", err 794 } 795 } 796 } 797 } else if options.Format == EXPLAIN_FORMAT_JSON { 798 return "", moerr.NewNYI(ctx, "explain format json") 799 } else if options.Format == EXPLAIN_FORMAT_DOT { 800 return "", moerr.NewNYI(ctx, "explain format dot") 801 } 802 return buf.String(), nil 803 } 804 805 func (ndesc *NodeDescribeImpl) GetWindowSpectListInfo(ctx context.Context, options *ExplainOptions) (string, error) { 806 buf := bytes.NewBuffer(make([]byte, 0, 300)) 807 buf.WriteString("Window Function: ") 808 if options.Format == EXPLAIN_FORMAT_TEXT { 809 first := true 810 for _, v := range ndesc.Node.GetWinSpecList() { 811 if !first { 812 buf.WriteString("\n") 813 } 814 first = false 815 err := describeExpr(ctx, v, options, buf) 816 if err != nil { 817 return "", err 818 } 819 } 820 } else if options.Format == EXPLAIN_FORMAT_JSON { 821 return "", moerr.NewNYI(ctx, "explain format json") 822 } else if options.Format == EXPLAIN_FORMAT_DOT { 823 return "", moerr.NewNYI(ctx, "explain format dot") 824 } 825 return buf.String(), nil 826 } 827 828 func (ndesc *NodeDescribeImpl) GetOrderByInfo(ctx context.Context, options *ExplainOptions) (string, error) { 829 buf := bytes.NewBuffer(make([]byte, 0, 300)) 830 if options.Format == EXPLAIN_FORMAT_TEXT { 831 buf.WriteString("Sort Key: ") 832 orderByDescImpl := NewOrderByDescribeImpl(ndesc.Node.OrderBy) 833 err := orderByDescImpl.GetDescription(ctx, options, buf) 834 if err != nil { 835 return "", err 836 } 837 } else if options.Format == EXPLAIN_FORMAT_JSON { 838 return "", moerr.NewNYI(ctx, "explain format json") 839 } else if options.Format == EXPLAIN_FORMAT_DOT { 840 return "", moerr.NewNYI(ctx, "explain format dot") 841 } 842 return buf.String(), nil 843 } 844 845 var _ NodeElemDescribe = (*CostDescribeImpl)(nil) 846 var _ NodeElemDescribe = (*ExprListDescribeImpl)(nil) 847 var _ NodeElemDescribe = (*OrderByDescribeImpl)(nil) 848 var _ NodeElemDescribe = (*WinSpecDescribeImpl)(nil) 849 var _ NodeElemDescribe = (*RowsetDataDescribeImpl)(nil) 850 var _ NodeElemDescribe = (*AnalyzeInfoDescribeImpl)(nil) 851 852 type AnalyzeInfoDescribeImpl struct { 853 AnalyzeInfo *plan.AnalyzeInfo 854 } 855 856 func NewAnalyzeInfoDescribeImpl(analyze *plan.AnalyzeInfo) *AnalyzeInfoDescribeImpl { 857 return &AnalyzeInfoDescribeImpl{ 858 AnalyzeInfo: analyze, 859 } 860 } 861 862 func (a AnalyzeInfoDescribeImpl) GetDescription(ctx context.Context, options *ExplainOptions, buf *bytes.Buffer) error { 863 fmt.Fprintf(buf, "timeConsumed=%dms", a.AnalyzeInfo.TimeConsumed/1000000) 864 865 var majorStr, minorStr string 866 switch options.NodeType { 867 case plan.Node_TABLE_SCAN, plan.Node_EXTERNAL_SCAN: 868 majorStr = "scan" 869 minorStr = "filter" 870 case plan.Node_JOIN: 871 majorStr = "probe" 872 minorStr = "build" 873 case plan.Node_AGG: 874 majorStr = "group" 875 minorStr = "mergegroup" 876 case plan.Node_SORT: 877 majorStr = "sort" 878 minorStr = "mergesort" 879 case plan.Node_FILTER: 880 majorStr = "" 881 minorStr = "filter" 882 } 883 884 majordop := len(a.AnalyzeInfo.TimeConsumedArrayMajor) 885 if majordop > 1 { 886 fmt.Fprintf(buf, " %v_time=[", majorStr) 887 sort.Slice(a.AnalyzeInfo.TimeConsumedArrayMajor, func(i, j int) bool { 888 return a.AnalyzeInfo.TimeConsumedArrayMajor[i] < a.AnalyzeInfo.TimeConsumedArrayMajor[j] 889 }) 890 if majordop > 4 { 891 var totalTime int64 892 for i := range a.AnalyzeInfo.TimeConsumedArrayMajor { 893 totalTime += a.AnalyzeInfo.TimeConsumedArrayMajor[i] 894 } 895 fmt.Fprintf(buf, 896 "total=%vms,min=%vms,max=%vms,dop=%v]", 897 totalTime/MILLION, 898 a.AnalyzeInfo.TimeConsumedArrayMajor[0]/MILLION, 899 a.AnalyzeInfo.TimeConsumedArrayMajor[len(a.AnalyzeInfo.TimeConsumedArrayMajor)-1]/MILLION, 900 majordop) 901 } else { 902 for i := range a.AnalyzeInfo.TimeConsumedArrayMajor { 903 if i != 0 { 904 fmt.Fprintf(buf, ",") 905 } 906 fmt.Fprintf(buf, "%vms", a.AnalyzeInfo.TimeConsumedArrayMajor[i]/MILLION) 907 } 908 fmt.Fprintf(buf, "]") 909 } 910 911 minordop := len(a.AnalyzeInfo.TimeConsumedArrayMinor) 912 if minordop > 0 { 913 if minorStr == "mergegroup" || minorStr == "mergesort" { 914 for i := range a.AnalyzeInfo.TimeConsumedArrayMinor { 915 if i != 0 { 916 a.AnalyzeInfo.TimeConsumedArrayMinor[0] += a.AnalyzeInfo.TimeConsumedArrayMinor[i] 917 } 918 } 919 a.AnalyzeInfo.TimeConsumedArrayMinor = a.AnalyzeInfo.TimeConsumedArrayMinor[:1] 920 } 921 922 fmt.Fprintf(buf, " %v_time=[", minorStr) 923 sort.Slice(a.AnalyzeInfo.TimeConsumedArrayMinor, func(i, j int) bool { 924 return a.AnalyzeInfo.TimeConsumedArrayMinor[i] < a.AnalyzeInfo.TimeConsumedArrayMinor[j] 925 }) 926 if minordop > 4 { 927 var totalTime int64 928 for i := range a.AnalyzeInfo.TimeConsumedArrayMinor { 929 totalTime += a.AnalyzeInfo.TimeConsumedArrayMinor[i] 930 } 931 fmt.Fprintf(buf, 932 "total=%vms,min=%vms,max=%vms,dop=%v]", 933 totalTime/MILLION, 934 a.AnalyzeInfo.TimeConsumedArrayMinor[0]/MILLION, 935 a.AnalyzeInfo.TimeConsumedArrayMinor[len(a.AnalyzeInfo.TimeConsumedArrayMinor)-1]/MILLION, 936 majordop) 937 } else { 938 for i := range a.AnalyzeInfo.TimeConsumedArrayMinor { 939 if i != 0 { 940 fmt.Fprintf(buf, ",") 941 } 942 fmt.Fprintf(buf, "%vms", a.AnalyzeInfo.TimeConsumedArrayMinor[i]/MILLION) 943 } 944 fmt.Fprintf(buf, "]") 945 } 946 } 947 } 948 949 fmt.Fprintf(buf, " waitTime=%dms", a.AnalyzeInfo.WaitTimeConsumed/MILLION) 950 fmt.Fprintf(buf, " inputRows=%d", a.AnalyzeInfo.InputRows) 951 fmt.Fprintf(buf, " outputRows=%d", a.AnalyzeInfo.OutputRows) 952 if a.AnalyzeInfo.InputSize < MB { 953 fmt.Fprintf(buf, " InputSize=%dbytes", a.AnalyzeInfo.InputSize) 954 } else if a.AnalyzeInfo.InputSize < 10*GB { 955 fmt.Fprintf(buf, " InputSize=%dmb", a.AnalyzeInfo.InputSize/MB) 956 } else { 957 fmt.Fprintf(buf, " InputSize=%dgb", a.AnalyzeInfo.InputSize/GB) 958 } 959 960 if a.AnalyzeInfo.OutputSize < MB { 961 fmt.Fprintf(buf, " OutputSize=%dbytes", a.AnalyzeInfo.OutputSize) 962 } else if a.AnalyzeInfo.OutputSize < 10*GB { 963 fmt.Fprintf(buf, " OutputSize=%dmb", a.AnalyzeInfo.OutputSize/MB) 964 } else { 965 fmt.Fprintf(buf, " OutputSize=%dgb", a.AnalyzeInfo.OutputSize/GB) 966 } 967 968 if a.AnalyzeInfo.MemorySize < MB { 969 fmt.Fprintf(buf, " MemorySize=%dbytes", a.AnalyzeInfo.MemorySize) 970 } else if a.AnalyzeInfo.MemorySize < 10*GB { 971 fmt.Fprintf(buf, " MemorySize=%dmb", a.AnalyzeInfo.MemorySize/MB) 972 } else { 973 fmt.Fprintf(buf, " MemorySize=%dgb", a.AnalyzeInfo.MemorySize/GB) 974 } 975 976 return nil 977 } 978 979 type CostDescribeImpl struct { 980 Stats *plan.Stats 981 } 982 983 func (c *CostDescribeImpl) GetDescription(ctx context.Context, options *ExplainOptions, buf *bytes.Buffer) error { 984 //var result string 985 if c.Stats == nil { 986 buf.WriteString(" (cost=0)") 987 } else { 988 var blockNumStr, hashmapSizeStr string 989 if c.Stats.BlockNum > 0 { 990 blockNumStr = " blockNum=" + strconv.FormatInt(int64(c.Stats.BlockNum), 10) 991 } 992 if c.Stats.HashmapStats != nil && c.Stats.HashmapStats.HashmapSize > 0 { 993 hashmapSizeStr = " hashmapSize=" + strconv.FormatFloat(c.Stats.HashmapStats.HashmapSize, 'f', 2, 64) 994 } 995 buf.WriteString(" (cost=" + strconv.FormatFloat(c.Stats.Cost, 'f', 2, 64) + 996 " outcnt=" + strconv.FormatFloat(c.Stats.Outcnt, 'f', 2, 64) + 997 " selectivity=" + strconv.FormatFloat(c.Stats.Selectivity, 'f', 4, 64) + 998 blockNumStr + hashmapSizeStr + ")") 999 } 1000 return nil 1001 } 1002 1003 type ExprListDescribeImpl struct { 1004 ExprList []*plan.Expr // ProjectList,OnList,FilterList,GroupBy,GroupingSet and so on 1005 } 1006 1007 func NewExprListDescribeImpl(ExprList []*plan.Expr) *ExprListDescribeImpl { 1008 return &ExprListDescribeImpl{ 1009 ExprList: ExprList, 1010 } 1011 } 1012 1013 func (e *ExprListDescribeImpl) GetDescription(ctx context.Context, options *ExplainOptions, buf *bytes.Buffer) error { 1014 first := true 1015 if options.Format == EXPLAIN_FORMAT_TEXT { 1016 for _, v := range e.ExprList { 1017 if !first { 1018 buf.WriteString(", ") 1019 } 1020 first = false 1021 err := describeExpr(ctx, v, options, buf) 1022 if err != nil { 1023 return err 1024 //return result, err 1025 } 1026 } 1027 } else if options.Format == EXPLAIN_FORMAT_JSON { 1028 return moerr.NewNYI(ctx, "explain format json") 1029 } else if options.Format == EXPLAIN_FORMAT_DOT { 1030 return moerr.NewNYI(ctx, "explain format dot") 1031 } 1032 return nil 1033 } 1034 1035 type OrderByDescribeImpl struct { 1036 OrderBy []*plan.OrderBySpec 1037 } 1038 1039 func NewOrderByDescribeImpl(OrderBy []*plan.OrderBySpec) *OrderByDescribeImpl { 1040 return &OrderByDescribeImpl{ 1041 OrderBy: OrderBy, 1042 } 1043 } 1044 1045 func (o *OrderByDescribeImpl) GetDescription(ctx context.Context, options *ExplainOptions, buf *bytes.Buffer) error { 1046 //var result string 1047 //buf := bytes.NewBuffer(make([]byte, 0, 120)) 1048 if options.Format == EXPLAIN_FORMAT_TEXT || options.Format == EXPLAIN_FORMAT_JSON { 1049 first := true 1050 for _, v := range o.OrderBy { 1051 if !first { 1052 buf.WriteString(", ") 1053 } 1054 first = false 1055 err := describeExpr(ctx, v.Expr, options, buf) 1056 if err != nil { 1057 return err 1058 } 1059 1060 flagKey := int32(v.Flag) 1061 orderbyFlag := plan.OrderBySpec_OrderByFlag_name[flagKey] 1062 buf.WriteString(" " + orderbyFlag) 1063 } 1064 } else if options.Format == EXPLAIN_FORMAT_DOT { 1065 return moerr.NewNYI(ctx, "explain format dot") 1066 } 1067 return nil 1068 } 1069 1070 type WinSpecDescribeImpl struct { 1071 WinSpec *plan.WindowSpec 1072 } 1073 1074 func (w *WinSpecDescribeImpl) GetDescription(ctx context.Context, options *ExplainOptions, buf *bytes.Buffer) error { 1075 // TODO implement me 1076 panic("implement me") 1077 } 1078 1079 type RowsetDataDescribeImpl struct { 1080 RowsetData *plan.RowsetData 1081 } 1082 1083 func (r *RowsetDataDescribeImpl) GetDescription(ctx context.Context, options *ExplainOptions, buf *bytes.Buffer) error { 1084 buf.WriteString("Value:") 1085 if r.RowsetData == nil { 1086 return nil 1087 } 1088 1089 first := true 1090 for index := range r.RowsetData.Cols { 1091 if !first { 1092 buf.WriteString(", ") 1093 } 1094 first = false 1095 buf.WriteString("\"*VALUES*\".column" + strconv.Itoa(index+1)) 1096 } 1097 return nil 1098 }