github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/acyclic/causet/embedded/explain.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package embedded 15 16 import ( 17 "bytes" 18 "fmt" 19 "strconv" 20 "strings" 21 22 "github.com/whtcorpsinc/BerolinaSQL/ast" 23 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 24 "github.com/whtcorpsinc/milevadb/causet" 25 "github.com/whtcorpsinc/milevadb/causet/soliton" 26 "github.com/whtcorpsinc/milevadb/memex" 27 "github.com/whtcorpsinc/milevadb/memex/aggregation" 28 "github.com/whtcorpsinc/milevadb/schemareplicant" 29 "github.com/whtcorpsinc/milevadb/soliton/stringutil" 30 "github.com/whtcorpsinc/milevadb/statistics" 31 "github.com/whtcorpsinc/milevadb/stochastikctx" 32 ) 33 34 // A plan is dataAccesser means it can access underlying data. 35 // Include `PhysicalBlockScan`, `PhysicalIndexScan`, `PointGetCauset`, `BatchPointScan` and `PhysicalMemBlock`. 36 // ExplainInfo = AccessObject + OperatorInfo 37 type dataAccesser interface { 38 39 // AccessObject return plan's `causet`, `partition` and `index`. 40 AccessObject() string 41 42 // OperatorInfo return other operator information to be explained. 43 OperatorInfo(normalized bool) string 44 } 45 46 type partitionAccesser interface { 47 accessObject(stochastikctx.Context) string 48 } 49 50 // ExplainInfo implements Causet interface. 51 func (p *PhysicalLock) ExplainInfo() string { 52 return fmt.Sprintf("%s %v", p.Lock.LockType.String(), p.Lock.WaitSec) 53 } 54 55 // ExplainID overrides the ExplainID in order to match different range. 56 func (p *PhysicalIndexScan) ExplainID() fmt.Stringer { 57 return stringutil.MemoizeStr(func() string { 58 if p.isFullScan() { 59 return "IndexFullScan_" + strconv.Itoa(p.id) 60 } 61 return "IndexRangeScan_" + strconv.Itoa(p.id) 62 }) 63 } 64 65 // ExplainInfo implements Causet interface. 66 func (p *PhysicalIndexScan) ExplainInfo() string { 67 return p.AccessObject() + ", " + p.OperatorInfo(false) 68 } 69 70 // ExplainNormalizedInfo implements Causet interface. 71 func (p *PhysicalIndexScan) ExplainNormalizedInfo() string { 72 return p.AccessObject() + ", " + p.OperatorInfo(true) 73 } 74 75 // AccessObject implements dataAccesser interface. 76 func (p *PhysicalIndexScan) AccessObject() string { 77 buffer := bytes.NewBufferString("") 78 tblName := p.Block.Name.O 79 if p.BlockAsName != nil && p.BlockAsName.O != "" { 80 tblName = p.BlockAsName.O 81 } 82 fmt.Fprintf(buffer, "causet:%s", tblName) 83 if p.isPartition { 84 if pi := p.Block.GetPartitionInfo(); pi != nil { 85 partitionName := pi.GetNameByID(p.physicalBlockID) 86 fmt.Fprintf(buffer, ", partition:%s", partitionName) 87 } 88 } 89 if len(p.Index.DeferredCausets) > 0 { 90 buffer.WriteString(", index:" + p.Index.Name.O + "(") 91 for i, idxDefCaus := range p.Index.DeferredCausets { 92 buffer.WriteString(idxDefCaus.Name.O) 93 if i+1 < len(p.Index.DeferredCausets) { 94 buffer.WriteString(", ") 95 } 96 } 97 buffer.WriteString(")") 98 } 99 return buffer.String() 100 } 101 102 // OperatorInfo implements dataAccesser interface. 103 func (p *PhysicalIndexScan) OperatorInfo(normalized bool) string { 104 buffer := bytes.NewBufferString("") 105 if len(p.rangeInfo) > 0 { 106 if !normalized { 107 fmt.Fprintf(buffer, "range: decided by %v, ", p.rangeInfo) 108 } 109 } else if p.haveCorDefCaus() { 110 if normalized { 111 fmt.Fprintf(buffer, "range: decided by %s, ", memex.SortedExplainNormalizedExpressionList(p.AccessCondition)) 112 } else { 113 fmt.Fprintf(buffer, "range: decided by %v, ", p.AccessCondition) 114 } 115 } else if len(p.Ranges) > 0 { 116 if normalized { 117 fmt.Fprint(buffer, "range:[?,?], ") 118 } else if !p.isFullScan() { 119 fmt.Fprint(buffer, "range:") 120 for _, idxRange := range p.Ranges { 121 fmt.Fprint(buffer, idxRange.String()+", ") 122 } 123 } 124 } 125 fmt.Fprintf(buffer, "keep order:%v, ", p.KeepOrder) 126 if p.Desc { 127 buffer.WriteString("desc, ") 128 } 129 if p.stats.StatsVersion == statistics.PseudoVersion && !normalized { 130 buffer.WriteString("stats:pseudo, ") 131 } 132 buffer.Truncate(buffer.Len() - 2) 133 return buffer.String() 134 } 135 136 func (p *PhysicalIndexScan) haveCorDefCaus() bool { 137 for _, cond := range p.AccessCondition { 138 if len(memex.ExtractCorDeferredCausets(cond)) > 0 { 139 return true 140 } 141 } 142 return false 143 } 144 145 func (p *PhysicalIndexScan) isFullScan() bool { 146 if len(p.rangeInfo) > 0 || p.haveCorDefCaus() { 147 return false 148 } 149 for _, ran := range p.Ranges { 150 if !ran.IsFullRange() { 151 return false 152 } 153 } 154 return true 155 } 156 157 // ExplainID overrides the ExplainID in order to match different range. 158 func (p *PhysicalBlockScan) ExplainID() fmt.Stringer { 159 return stringutil.MemoizeStr(func() string { 160 if p.isChildOfIndexLookUp { 161 return "BlockRowIDScan_" + strconv.Itoa(p.id) 162 } else if p.isFullScan() { 163 return "BlockFullScan_" + strconv.Itoa(p.id) 164 } 165 return "BlockRangeScan_" + strconv.Itoa(p.id) 166 }) 167 } 168 169 // ExplainInfo implements Causet interface. 170 func (p *PhysicalBlockScan) ExplainInfo() string { 171 return p.AccessObject() + ", " + p.OperatorInfo(false) 172 } 173 174 // ExplainNormalizedInfo implements Causet interface. 175 func (p *PhysicalBlockScan) ExplainNormalizedInfo() string { 176 return p.AccessObject() + ", " + p.OperatorInfo(true) 177 } 178 179 // AccessObject implements dataAccesser interface. 180 func (p *PhysicalBlockScan) AccessObject() string { 181 buffer := bytes.NewBufferString("") 182 tblName := p.Block.Name.O 183 if p.BlockAsName != nil && p.BlockAsName.O != "" { 184 tblName = p.BlockAsName.O 185 } 186 fmt.Fprintf(buffer, "causet:%s", tblName) 187 if p.isPartition { 188 if pi := p.Block.GetPartitionInfo(); pi != nil { 189 partitionName := pi.GetNameByID(p.physicalBlockID) 190 fmt.Fprintf(buffer, ", partition:%s", partitionName) 191 } 192 } 193 return buffer.String() 194 } 195 196 // OperatorInfo implements dataAccesser interface. 197 func (p *PhysicalBlockScan) OperatorInfo(normalized bool) string { 198 buffer := bytes.NewBufferString("") 199 for i, pkDefCaus := range p.PkDefCauss { 200 var fmtStr string 201 switch i { 202 case 0: 203 fmtStr = "pk defcaus: (%s, " 204 case len(p.PkDefCauss) - 1: 205 fmtStr = "%s)" 206 default: 207 fmtStr = "%s, " 208 } 209 fmt.Fprintf(buffer, fmtStr, pkDefCaus.ExplainInfo()) 210 } 211 if len(p.rangeDecidedBy) > 0 { 212 fmt.Fprintf(buffer, "range: decided by %v, ", p.rangeDecidedBy) 213 } else if p.haveCorDefCaus() { 214 if normalized { 215 fmt.Fprintf(buffer, "range: decided by %s, ", memex.SortedExplainNormalizedExpressionList(p.AccessCondition)) 216 } else { 217 fmt.Fprintf(buffer, "range: decided by %v, ", p.AccessCondition) 218 } 219 } else if len(p.Ranges) > 0 { 220 if normalized { 221 fmt.Fprint(buffer, "range:[?,?], ") 222 } else if !p.isFullScan() { 223 fmt.Fprint(buffer, "range:") 224 for _, idxRange := range p.Ranges { 225 fmt.Fprint(buffer, idxRange.String()+", ") 226 } 227 } 228 } 229 fmt.Fprintf(buffer, "keep order:%v, ", p.KeepOrder) 230 if p.Desc { 231 buffer.WriteString("desc, ") 232 } 233 if p.stats.StatsVersion == statistics.PseudoVersion && !normalized { 234 buffer.WriteString("stats:pseudo, ") 235 } 236 if p.IsGlobalRead { 237 buffer.WriteString("global read, ") 238 } 239 buffer.Truncate(buffer.Len() - 2) 240 return buffer.String() 241 } 242 243 func (p *PhysicalBlockScan) haveCorDefCaus() bool { 244 for _, cond := range p.AccessCondition { 245 if len(memex.ExtractCorDeferredCausets(cond)) > 0 { 246 return true 247 } 248 } 249 return false 250 } 251 252 func (p *PhysicalBlockScan) isFullScan() bool { 253 if len(p.rangeDecidedBy) > 0 || p.haveCorDefCaus() { 254 return false 255 } 256 for _, ran := range p.Ranges { 257 if !ran.IsFullRange() { 258 return false 259 } 260 } 261 return true 262 } 263 264 // ExplainInfo implements Causet interface. 265 func (p *PhysicalBlockReader) ExplainInfo() string { 266 return "data:" + p.blockCauset.ExplainID().String() 267 } 268 269 // ExplainNormalizedInfo implements Causet interface. 270 func (p *PhysicalBlockReader) ExplainNormalizedInfo() string { 271 return "" 272 } 273 274 func (p *PhysicalBlockReader) accessObject(sctx stochastikctx.Context) string { 275 ts := p.BlockCausets[0].(*PhysicalBlockScan) 276 pi := ts.Block.GetPartitionInfo() 277 if pi == nil || !sctx.GetStochastikVars().UseDynamicPartitionPrune() { 278 return "" 279 } 280 281 is := schemareplicant.GetSchemaReplicant(sctx) 282 tmp, ok := is.BlockByID(ts.Block.ID) 283 if !ok { 284 return "partition causet not found" + strconv.FormatInt(ts.Block.ID, 10) 285 } 286 tbl := tmp.(causet.PartitionedBlock) 287 288 return partitionAccessObject(sctx, tbl, pi, &p.PartitionInfo) 289 } 290 291 func partitionAccessObject(sctx stochastikctx.Context, tbl causet.PartitionedBlock, pi *perceptron.PartitionInfo, partBlock *PartitionInfo) string { 292 var buffer bytes.Buffer 293 idxArr, err := PartitionPruning(sctx, tbl, partBlock.PruningConds, partBlock.PartitionNames, partBlock.DeferredCausets, partBlock.DeferredCausetNames) 294 if err != nil { 295 return "partition pruning error" + err.Error() 296 } 297 298 if len(idxArr) == 0 { 299 return "partition:dual" 300 } 301 302 if len(idxArr) == 1 && idxArr[0] == FullRange { 303 return "partition:all" 304 } 305 306 for i, idx := range idxArr { 307 if i == 0 { 308 buffer.WriteString("partition:") 309 } else { 310 buffer.WriteString(",") 311 } 312 buffer.WriteString(pi.Definitions[idx].Name.O) 313 } 314 315 return buffer.String() 316 } 317 318 // OperatorInfo return other operator information to be explained. 319 func (p *PhysicalBlockReader) OperatorInfo(normalized bool) string { 320 return "data:" + p.blockCauset.ExplainID().String() 321 } 322 323 // ExplainInfo implements Causet interface. 324 func (p *PhysicalIndexReader) ExplainInfo() string { 325 return "index:" + p.indexCauset.ExplainID().String() 326 } 327 328 // ExplainNormalizedInfo implements Causet interface. 329 func (p *PhysicalIndexReader) ExplainNormalizedInfo() string { 330 return p.ExplainInfo() 331 } 332 333 func (p *PhysicalIndexReader) accessObject(sctx stochastikctx.Context) string { 334 ts := p.IndexCausets[0].(*PhysicalIndexScan) 335 pi := ts.Block.GetPartitionInfo() 336 if pi == nil || !sctx.GetStochastikVars().UseDynamicPartitionPrune() { 337 return "" 338 } 339 340 var buffer bytes.Buffer 341 is := schemareplicant.GetSchemaReplicant(sctx) 342 tmp, ok := is.BlockByID(ts.Block.ID) 343 if !ok { 344 fmt.Fprintf(&buffer, "partition causet not found: %d", ts.Block.ID) 345 return buffer.String() 346 } 347 348 tbl := tmp.(causet.PartitionedBlock) 349 return partitionAccessObject(sctx, tbl, pi, &p.PartitionInfo) 350 } 351 352 // ExplainInfo implements Causet interface. 353 func (p *PhysicalIndexLookUpReader) ExplainInfo() string { 354 // The children can be inferred by the relation symbol. 355 if p.PushedLimit != nil { 356 return fmt.Sprintf("limit embedded(offset:%v, count:%v)", p.PushedLimit.Offset, p.PushedLimit.Count) 357 } 358 return "" 359 } 360 361 func (p *PhysicalIndexLookUpReader) accessObject(sctx stochastikctx.Context) string { 362 ts := p.BlockCausets[0].(*PhysicalBlockScan) 363 pi := ts.Block.GetPartitionInfo() 364 if pi == nil || !sctx.GetStochastikVars().UseDynamicPartitionPrune() { 365 return "" 366 } 367 368 var buffer bytes.Buffer 369 is := schemareplicant.GetSchemaReplicant(sctx) 370 tmp, ok := is.BlockByID(ts.Block.ID) 371 if !ok { 372 fmt.Fprintf(&buffer, "partition causet not found: %d", ts.Block.ID) 373 return buffer.String() 374 } 375 376 tbl := tmp.(causet.PartitionedBlock) 377 return partitionAccessObject(sctx, tbl, pi, &p.PartitionInfo) 378 } 379 380 // ExplainInfo implements Causet interface. 381 func (p *PhysicalIndexMergeReader) ExplainInfo() string { 382 return "" 383 } 384 385 func (p *PhysicalIndexMergeReader) accessObject(sctx stochastikctx.Context) string { 386 ts := p.BlockCausets[0].(*PhysicalBlockScan) 387 pi := ts.Block.GetPartitionInfo() 388 if pi == nil || !sctx.GetStochastikVars().UseDynamicPartitionPrune() { 389 return "" 390 } 391 392 is := schemareplicant.GetSchemaReplicant(sctx) 393 tmp, ok := is.BlockByID(ts.Block.ID) 394 if !ok { 395 return "partition causet not found" + strconv.FormatInt(ts.Block.ID, 10) 396 } 397 tbl := tmp.(causet.PartitionedBlock) 398 399 return partitionAccessObject(sctx, tbl, pi, &p.PartitionInfo) 400 } 401 402 // ExplainInfo implements Causet interface. 403 func (p *PhysicalUnionScan) ExplainInfo() string { 404 return string(memex.SortedExplainExpressionList(p.Conditions)) 405 } 406 407 // ExplainInfo implements Causet interface. 408 func (p *PhysicalSelection) ExplainInfo() string { 409 return string(memex.SortedExplainExpressionList(p.Conditions)) 410 } 411 412 // ExplainNormalizedInfo implements Causet interface. 413 func (p *PhysicalSelection) ExplainNormalizedInfo() string { 414 return string(memex.SortedExplainNormalizedExpressionList(p.Conditions)) 415 } 416 417 // ExplainInfo implements Causet interface. 418 func (p *PhysicalProjection) ExplainInfo() string { 419 return memex.ExplainExpressionList(p.Exprs, p.schemaReplicant) 420 } 421 422 // ExplainNormalizedInfo implements Causet interface. 423 func (p *PhysicalProjection) ExplainNormalizedInfo() string { 424 return string(memex.SortedExplainNormalizedExpressionList(p.Exprs)) 425 } 426 427 // ExplainInfo implements Causet interface. 428 func (p *PhysicalBlockDual) ExplainInfo() string { 429 return fmt.Sprintf("rows:%v", p.RowCount) 430 } 431 432 // ExplainInfo implements Causet interface. 433 func (p *PhysicalSort) ExplainInfo() string { 434 buffer := bytes.NewBufferString("") 435 return explainByItems(buffer, p.ByItems).String() 436 } 437 438 // ExplainInfo implements Causet interface. 439 func (p *PhysicalLimit) ExplainInfo() string { 440 return fmt.Sprintf("offset:%v, count:%v", p.Offset, p.Count) 441 } 442 443 // ExplainInfo implements Causet interface. 444 func (p *basePhysicalAgg) ExplainInfo() string { 445 return p.explainInfo(false) 446 } 447 448 func (p *basePhysicalAgg) explainInfo(normalized bool) string { 449 sortedExplainExpressionList := memex.SortedExplainExpressionList 450 if normalized { 451 sortedExplainExpressionList = memex.SortedExplainNormalizedExpressionList 452 } 453 454 builder := &strings.Builder{} 455 if len(p.GroupByItems) > 0 { 456 fmt.Fprintf(builder, "group by:%s, ", 457 sortedExplainExpressionList(p.GroupByItems)) 458 } 459 for i := 0; i < len(p.AggFuncs); i++ { 460 builder.WriteString("funcs:") 461 var colName string 462 if normalized { 463 colName = p.schemaReplicant.DeferredCausets[i].ExplainNormalizedInfo() 464 } else { 465 colName = p.schemaReplicant.DeferredCausets[i].ExplainInfo() 466 } 467 fmt.Fprintf(builder, "%v->%v", aggregation.ExplainAggFunc(p.AggFuncs[i], normalized), colName) 468 if i+1 < len(p.AggFuncs) { 469 builder.WriteString(", ") 470 } 471 } 472 return builder.String() 473 } 474 475 // ExplainNormalizedInfo implements Causet interface. 476 func (p *basePhysicalAgg) ExplainNormalizedInfo() string { 477 return p.explainInfo(true) 478 } 479 480 // ExplainInfo implements Causet interface. 481 func (p *PhysicalIndexJoin) ExplainInfo() string { 482 return p.explainInfo(false) 483 } 484 485 func (p *PhysicalIndexJoin) explainInfo(normalized bool) string { 486 sortedExplainExpressionList := memex.SortedExplainExpressionList 487 if normalized { 488 sortedExplainExpressionList = memex.SortedExplainNormalizedExpressionList 489 } 490 491 buffer := bytes.NewBufferString(p.JoinType.String()) 492 if normalized { 493 fmt.Fprintf(buffer, ", inner:%s", p.Children()[p.InnerChildIdx].TP()) 494 } else { 495 fmt.Fprintf(buffer, ", inner:%s", p.Children()[p.InnerChildIdx].ExplainID()) 496 } 497 if len(p.OuterJoinKeys) > 0 { 498 fmt.Fprintf(buffer, ", outer key:%s", 499 memex.ExplainDeferredCausetList(p.OuterJoinKeys)) 500 } 501 if len(p.InnerJoinKeys) > 0 { 502 fmt.Fprintf(buffer, ", inner key:%s", 503 memex.ExplainDeferredCausetList(p.InnerJoinKeys)) 504 } 505 if len(p.LeftConditions) > 0 { 506 fmt.Fprintf(buffer, ", left cond:%s", 507 sortedExplainExpressionList(p.LeftConditions)) 508 } 509 if len(p.RightConditions) > 0 { 510 fmt.Fprintf(buffer, ", right cond:%s", 511 sortedExplainExpressionList(p.RightConditions)) 512 } 513 if len(p.OtherConditions) > 0 { 514 fmt.Fprintf(buffer, ", other cond:%s", 515 sortedExplainExpressionList(p.OtherConditions)) 516 } 517 return buffer.String() 518 } 519 520 // ExplainNormalizedInfo implements Causet interface. 521 func (p *PhysicalIndexJoin) ExplainNormalizedInfo() string { 522 return p.explainInfo(true) 523 } 524 525 // ExplainInfo implements Causet interface. 526 func (p *PhysicalHashJoin) ExplainInfo() string { 527 return p.explainInfo(false) 528 } 529 530 // ExplainNormalizedInfo implements Causet interface. 531 func (p *PhysicalHashJoin) ExplainNormalizedInfo() string { 532 return p.explainInfo(true) 533 } 534 535 func (p *PhysicalHashJoin) explainInfo(normalized bool) string { 536 sortedExplainExpressionList := memex.SortedExplainExpressionList 537 if normalized { 538 sortedExplainExpressionList = memex.SortedExplainNormalizedExpressionList 539 } 540 541 buffer := new(bytes.Buffer) 542 543 if len(p.EqualConditions) == 0 { 544 buffer.WriteString("CARTESIAN ") 545 } 546 547 buffer.WriteString(p.JoinType.String()) 548 549 if len(p.EqualConditions) > 0 { 550 if normalized { 551 fmt.Fprintf(buffer, ", equal:%s", memex.SortedExplainNormalizedScalarFuncList(p.EqualConditions)) 552 } else { 553 fmt.Fprintf(buffer, ", equal:%v", p.EqualConditions) 554 } 555 } 556 if len(p.LeftConditions) > 0 { 557 if normalized { 558 fmt.Fprintf(buffer, ", left cond:%s", memex.SortedExplainNormalizedExpressionList(p.LeftConditions)) 559 } else { 560 fmt.Fprintf(buffer, ", left cond:%s", p.LeftConditions) 561 } 562 } 563 if len(p.RightConditions) > 0 { 564 fmt.Fprintf(buffer, ", right cond:%s", 565 sortedExplainExpressionList(p.RightConditions)) 566 } 567 if len(p.OtherConditions) > 0 { 568 fmt.Fprintf(buffer, ", other cond:%s", 569 sortedExplainExpressionList(p.OtherConditions)) 570 } 571 return buffer.String() 572 } 573 574 // ExplainInfo implements Causet interface. 575 func (p *PhysicalMergeJoin) ExplainInfo() string { 576 return p.explainInfo(false) 577 } 578 579 func (p *PhysicalMergeJoin) explainInfo(normalized bool) string { 580 sortedExplainExpressionList := memex.SortedExplainExpressionList 581 if normalized { 582 sortedExplainExpressionList = memex.SortedExplainNormalizedExpressionList 583 } 584 585 buffer := bytes.NewBufferString(p.JoinType.String()) 586 if len(p.LeftJoinKeys) > 0 { 587 fmt.Fprintf(buffer, ", left key:%s", 588 memex.ExplainDeferredCausetList(p.LeftJoinKeys)) 589 } 590 if len(p.RightJoinKeys) > 0 { 591 fmt.Fprintf(buffer, ", right key:%s", 592 memex.ExplainDeferredCausetList(p.RightJoinKeys)) 593 } 594 if len(p.LeftConditions) > 0 { 595 if normalized { 596 fmt.Fprintf(buffer, ", left cond:%s", memex.SortedExplainNormalizedExpressionList(p.LeftConditions)) 597 } else { 598 fmt.Fprintf(buffer, ", left cond:%s", p.LeftConditions) 599 } 600 } 601 if len(p.RightConditions) > 0 { 602 fmt.Fprintf(buffer, ", right cond:%s", 603 sortedExplainExpressionList(p.RightConditions)) 604 } 605 if len(p.OtherConditions) > 0 { 606 fmt.Fprintf(buffer, ", other cond:%s", 607 sortedExplainExpressionList(p.OtherConditions)) 608 } 609 return buffer.String() 610 } 611 612 // ExplainNormalizedInfo implements Causet interface. 613 func (p *PhysicalMergeJoin) ExplainNormalizedInfo() string { 614 return p.explainInfo(true) 615 } 616 617 // ExplainInfo implements Causet interface. 618 func (p *PhysicalBroadCastJoin) ExplainInfo() string { 619 return p.explainInfo() 620 } 621 622 // ExplainNormalizedInfo implements Causet interface. 623 func (p *PhysicalBroadCastJoin) ExplainNormalizedInfo() string { 624 return p.explainInfo() 625 } 626 627 func (p *PhysicalBroadCastJoin) explainInfo() string { 628 buffer := new(bytes.Buffer) 629 630 buffer.WriteString(p.JoinType.String()) 631 632 if len(p.LeftJoinKeys) > 0 { 633 fmt.Fprintf(buffer, ", left key:%s", 634 memex.ExplainDeferredCausetList(p.LeftJoinKeys)) 635 } 636 if len(p.RightJoinKeys) > 0 { 637 fmt.Fprintf(buffer, ", right key:%s", 638 memex.ExplainDeferredCausetList(p.RightJoinKeys)) 639 } 640 return buffer.String() 641 } 642 643 // ExplainInfo implements Causet interface. 644 func (p *PhysicalTopN) ExplainInfo() string { 645 buffer := bytes.NewBufferString("") 646 buffer = explainByItems(buffer, p.ByItems) 647 fmt.Fprintf(buffer, ", offset:%v, count:%v", p.Offset, p.Count) 648 return buffer.String() 649 } 650 651 // ExplainNormalizedInfo implements Causet interface. 652 func (p *PhysicalTopN) ExplainNormalizedInfo() string { 653 buffer := bytes.NewBufferString("") 654 buffer = explainNormalizedByItems(buffer, p.ByItems) 655 return buffer.String() 656 } 657 658 func (p *PhysicalWindow) formatFrameBound(buffer *bytes.Buffer, bound *FrameBound) { 659 if bound.Type == ast.CurrentRow { 660 buffer.WriteString("current event") 661 return 662 } 663 if bound.UnBounded { 664 buffer.WriteString("unbounded") 665 } else if len(bound.CalcFuncs) > 0 { 666 sf := bound.CalcFuncs[0].(*memex.ScalarFunction) 667 switch sf.FuncName.L { 668 case ast.DateAdd, ast.DateSub: 669 // For `interval '2:30' minute_second`. 670 fmt.Fprintf(buffer, "interval %s %s", sf.GetArgs()[1].ExplainInfo(), sf.GetArgs()[2].ExplainInfo()) 671 case ast.Plus, ast.Minus: 672 // For `1 preceding` of range frame. 673 fmt.Fprintf(buffer, "%s", sf.GetArgs()[1].ExplainInfo()) 674 } 675 } else { 676 fmt.Fprintf(buffer, "%d", bound.Num) 677 } 678 if bound.Type == ast.Preceding { 679 buffer.WriteString(" preceding") 680 } else { 681 buffer.WriteString(" following") 682 } 683 } 684 685 // ExplainInfo implements Causet interface. 686 func (p *PhysicalWindow) ExplainInfo() string { 687 buffer := bytes.NewBufferString("") 688 formatWindowFuncDescs(buffer, p.WindowFuncDescs, p.schemaReplicant) 689 buffer.WriteString(" over(") 690 isFirst := true 691 if len(p.PartitionBy) > 0 { 692 buffer.WriteString("partition by ") 693 for i, item := range p.PartitionBy { 694 fmt.Fprintf(buffer, "%s", item.DefCaus.ExplainInfo()) 695 if i+1 < len(p.PartitionBy) { 696 buffer.WriteString(", ") 697 } 698 } 699 isFirst = false 700 } 701 if len(p.OrderBy) > 0 { 702 if !isFirst { 703 buffer.WriteString(" ") 704 } 705 buffer.WriteString("order by ") 706 for i, item := range p.OrderBy { 707 if item.Desc { 708 fmt.Fprintf(buffer, "%s desc", item.DefCaus.ExplainInfo()) 709 } else { 710 fmt.Fprintf(buffer, "%s", item.DefCaus.ExplainInfo()) 711 } 712 713 if i+1 < len(p.OrderBy) { 714 buffer.WriteString(", ") 715 } 716 } 717 isFirst = false 718 } 719 if p.Frame != nil { 720 if !isFirst { 721 buffer.WriteString(" ") 722 } 723 if p.Frame.Type == ast.Rows { 724 buffer.WriteString("rows") 725 } else { 726 buffer.WriteString("range") 727 } 728 buffer.WriteString(" between ") 729 p.formatFrameBound(buffer, p.Frame.Start) 730 buffer.WriteString(" and ") 731 p.formatFrameBound(buffer, p.Frame.End) 732 } 733 buffer.WriteString(")") 734 return buffer.String() 735 } 736 737 // ExplainInfo implements Causet interface. 738 func (p *PhysicalShuffle) ExplainInfo() string { 739 buffer := bytes.NewBufferString("") 740 fmt.Fprintf(buffer, "execution info: concurrency:%v, data source:%v", p.Concurrency, p.DataSource.ExplainID()) 741 return buffer.String() 742 } 743 744 func formatWindowFuncDescs(buffer *bytes.Buffer, descs []*aggregation.WindowFuncDesc, schemaReplicant *memex.Schema) *bytes.Buffer { 745 winFuncStartIdx := len(schemaReplicant.DeferredCausets) - len(descs) 746 for i, desc := range descs { 747 if i != 0 { 748 buffer.WriteString(", ") 749 } 750 fmt.Fprintf(buffer, "%v->%v", desc, schemaReplicant.DeferredCausets[winFuncStartIdx+i]) 751 } 752 return buffer 753 } 754 755 // ExplainInfo implements Causet interface. 756 func (p *LogicalJoin) ExplainInfo() string { 757 buffer := bytes.NewBufferString(p.JoinType.String()) 758 if len(p.EqualConditions) > 0 { 759 fmt.Fprintf(buffer, ", equal:%v", p.EqualConditions) 760 } 761 if len(p.LeftConditions) > 0 { 762 fmt.Fprintf(buffer, ", left cond:%s", 763 memex.SortedExplainExpressionList(p.LeftConditions)) 764 } 765 if len(p.RightConditions) > 0 { 766 fmt.Fprintf(buffer, ", right cond:%s", 767 memex.SortedExplainExpressionList(p.RightConditions)) 768 } 769 if len(p.OtherConditions) > 0 { 770 fmt.Fprintf(buffer, ", other cond:%s", 771 memex.SortedExplainExpressionList(p.OtherConditions)) 772 } 773 return buffer.String() 774 } 775 776 // ExplainInfo implements Causet interface. 777 func (p *LogicalAggregation) ExplainInfo() string { 778 buffer := bytes.NewBufferString("") 779 if len(p.GroupByItems) > 0 { 780 fmt.Fprintf(buffer, "group by:%s, ", 781 memex.SortedExplainExpressionList(p.GroupByItems)) 782 } 783 if len(p.AggFuncs) > 0 { 784 buffer.WriteString("funcs:") 785 for i, agg := range p.AggFuncs { 786 buffer.WriteString(aggregation.ExplainAggFunc(agg, false)) 787 if i+1 < len(p.AggFuncs) { 788 buffer.WriteString(", ") 789 } 790 } 791 } 792 return buffer.String() 793 } 794 795 // ExplainInfo implements Causet interface. 796 func (p *LogicalProjection) ExplainInfo() string { 797 return memex.ExplainExpressionList(p.Exprs, p.schemaReplicant) 798 } 799 800 // ExplainInfo implements Causet interface. 801 func (p *LogicalSelection) ExplainInfo() string { 802 return string(memex.SortedExplainExpressionList(p.Conditions)) 803 } 804 805 // ExplainInfo implements Causet interface. 806 func (p *LogicalApply) ExplainInfo() string { 807 return p.LogicalJoin.ExplainInfo() 808 } 809 810 // ExplainInfo implements Causet interface. 811 func (p *LogicalBlockDual) ExplainInfo() string { 812 return fmt.Sprintf("rowcount:%d", p.RowCount) 813 } 814 815 // ExplainInfo implements Causet interface. 816 func (p *DataSource) ExplainInfo() string { 817 buffer := bytes.NewBufferString("") 818 tblName := p.blockInfo.Name.O 819 if p.BlockAsName != nil && p.BlockAsName.O != "" { 820 tblName = p.BlockAsName.O 821 } 822 fmt.Fprintf(buffer, "causet:%s", tblName) 823 if p.isPartition { 824 if pi := p.blockInfo.GetPartitionInfo(); pi != nil { 825 partitionName := pi.GetNameByID(p.physicalBlockID) 826 fmt.Fprintf(buffer, ", partition:%s", partitionName) 827 } 828 } 829 return buffer.String() 830 } 831 832 // ExplainInfo implements Causet interface. 833 func (p *LogicalUnionScan) ExplainInfo() string { 834 buffer := bytes.NewBufferString("") 835 fmt.Fprintf(buffer, "conds:%s", 836 memex.SortedExplainExpressionList(p.conditions)) 837 fmt.Fprintf(buffer, ", handle:%s", p.handleDefCauss) 838 return buffer.String() 839 } 840 841 func explainByItems(buffer *bytes.Buffer, byItems []*soliton.ByItems) *bytes.Buffer { 842 for i, item := range byItems { 843 if item.Desc { 844 fmt.Fprintf(buffer, "%s:desc", item.Expr.ExplainInfo()) 845 } else { 846 fmt.Fprintf(buffer, "%s", item.Expr.ExplainInfo()) 847 } 848 849 if i+1 < len(byItems) { 850 buffer.WriteString(", ") 851 } 852 } 853 return buffer 854 } 855 856 func explainNormalizedByItems(buffer *bytes.Buffer, byItems []*soliton.ByItems) *bytes.Buffer { 857 for i, item := range byItems { 858 if item.Desc { 859 fmt.Fprintf(buffer, "%s:desc", item.Expr.ExplainNormalizedInfo()) 860 } else { 861 fmt.Fprintf(buffer, "%s", item.Expr.ExplainNormalizedInfo()) 862 } 863 864 if i+1 < len(byItems) { 865 buffer.WriteString(", ") 866 } 867 } 868 return buffer 869 } 870 871 // ExplainInfo implements Causet interface. 872 func (p *LogicalSort) ExplainInfo() string { 873 buffer := bytes.NewBufferString("") 874 return explainByItems(buffer, p.ByItems).String() 875 } 876 877 // ExplainInfo implements Causet interface. 878 func (p *LogicalTopN) ExplainInfo() string { 879 buffer := bytes.NewBufferString("") 880 buffer = explainByItems(buffer, p.ByItems) 881 fmt.Fprintf(buffer, ", offset:%v, count:%v", p.Offset, p.Count) 882 return buffer.String() 883 } 884 885 // ExplainInfo implements Causet interface. 886 func (p *LogicalLimit) ExplainInfo() string { 887 return fmt.Sprintf("offset:%v, count:%v", p.Offset, p.Count) 888 } 889 890 // ExplainInfo implements Causet interface. 891 func (p *LogicalBlockScan) ExplainInfo() string { 892 buffer := bytes.NewBufferString(p.Source.ExplainInfo()) 893 if p.Source.handleDefCauss != nil { 894 fmt.Fprintf(buffer, ", pk col:%s", p.Source.handleDefCauss) 895 } 896 if len(p.AccessConds) > 0 { 897 fmt.Fprintf(buffer, ", cond:%v", p.AccessConds) 898 } 899 return buffer.String() 900 } 901 902 // ExplainInfo implements Causet interface. 903 func (p *LogicalIndexScan) ExplainInfo() string { 904 buffer := bytes.NewBufferString(p.Source.ExplainInfo()) 905 index := p.Index 906 if len(index.DeferredCausets) > 0 { 907 buffer.WriteString(", index:") 908 for i, idxDefCaus := range index.DeferredCausets { 909 buffer.WriteString(idxDefCaus.Name.O) 910 if i+1 < len(index.DeferredCausets) { 911 buffer.WriteString(", ") 912 } 913 } 914 } 915 if len(p.AccessConds) > 0 { 916 fmt.Fprintf(buffer, ", cond:%v", p.AccessConds) 917 } 918 return buffer.String() 919 } 920 921 // ExplainInfo implements Causet interface. 922 func (p *EinsteinDBSingleGather) ExplainInfo() string { 923 buffer := bytes.NewBufferString(p.Source.ExplainInfo()) 924 if p.IsIndexGather { 925 buffer.WriteString(", index:" + p.Index.Name.String()) 926 } 927 return buffer.String() 928 } 929 930 // MetricBlockTimeFormat is the time format for metric causet explain and format. 931 const MetricBlockTimeFormat = "2006-01-02 15:04:05.999" 932 933 // ExplainInfo implements Causet interface. 934 func (p *PhysicalMemBlock) ExplainInfo() string { 935 accessObject, operatorInfo := p.AccessObject(), p.OperatorInfo(false) 936 if len(operatorInfo) == 0 { 937 return accessObject 938 } 939 return accessObject + ", " + operatorInfo 940 } 941 942 // AccessObject implements dataAccesser interface. 943 func (p *PhysicalMemBlock) AccessObject() string { 944 return "causet:" + p.Block.Name.O 945 } 946 947 // OperatorInfo implements dataAccesser interface. 948 func (p *PhysicalMemBlock) OperatorInfo(_ bool) string { 949 if p.Extractor != nil { 950 return p.Extractor.explainInfo(p) 951 } 952 return "" 953 }