@@ -131,6 +131,8 @@ func (p *PhysicalIndexScan) GetPlanCostVer2(taskType property.TaskType, option *
131131
132132 p .PlanCostVer2 = scanCostVer2 (option , rows , rowSize , scanFactor )
133133 p .PlanCostInit = true
134+ // Multiply by cost factor - defaults to 1, but can be increased/decreased to influence the cost model
135+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().IndexScanCostFactor )
134136 return p .PlanCostVer2 , nil
135137}
136138
@@ -185,6 +187,30 @@ func (p *PhysicalTableScan) GetPlanCostVer2(taskType property.TaskType, option *
185187 }
186188
187189 p .PlanCostInit = true
190+ // Multiply by cost factor - defaults to 1, but can be increased/decreased to influence the cost model
191+ if p .isChildOfIndexLookUp {
192+ // This is a RowID table scan (child of IndexLookUp)
193+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().TableRowIDScanCostFactor )
194+ } else {
195+ var unsignedIntHandle bool
196+ if p .Table .PKIsHandle {
197+ if pkColInfo := p .Table .GetPkColInfo (); pkColInfo != nil {
198+ unsignedIntHandle = mysql .HasUnsignedFlag (pkColInfo .GetFlag ())
199+ }
200+ }
201+ hasFullRangeScan := ranger .HasFullRange (p .Ranges , unsignedIntHandle )
202+ if ! hasFullRangeScan {
203+ // This is a table range scan (predicate exists on the PK)
204+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().TableRangeScanCostFactor )
205+ } else {
206+ // This is a table full scan
207+ if p .StoreType == kv .TiFlash {
208+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().TableTiFlashScanCostFactor )
209+ } else {
210+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().TableFullScanCostFactor )
211+ }
212+ }
213+ }
188214 return p .PlanCostVer2 , nil
189215}
190216
@@ -210,6 +236,8 @@ func (p *PhysicalIndexReader) GetPlanCostVer2(taskType property.TaskType, option
210236
211237 p .PlanCostVer2 = costusage .DivCostVer2 (costusage .SumCostVer2 (childCost , netCost ), concurrency )
212238 p .PlanCostInit = true
239+ // Multiply by cost factor - defaults to 1, but can be increased/decreased to influence the cost model
240+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().IndexReaderCostFactor )
213241 return p .PlanCostVer2 , nil
214242}
215243
@@ -245,6 +273,8 @@ func (p *PhysicalTableReader) GetPlanCostVer2(taskType property.TaskType, option
245273 ! hasCostFlag (option .CostFlag , costusage .CostFlagRecalculate ) { // show the real cost in explain-statements
246274 p .PlanCostVer2 = costusage .DivCostVer2 (p .PlanCostVer2 , 1000000000 )
247275 }
276+ // Multiply by cost factor - defaults to 1, but can be increased/decreased to influence the cost model
277+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().TableReaderCostFactor )
248278 return p .PlanCostVer2 , nil
249279}
250280
@@ -306,6 +336,12 @@ func (p *PhysicalIndexLookUpReader) GetPlanCostVer2(taskType property.TaskType,
306336 }
307337
308338 p .PlanCostInit = true
339+ if p .PushedLimit != nil && tableRows <= float64 (p .PushedLimit .Count ) {
340+ // Multiply by limit cost factor - defaults to 1, but can be increased/decreased to influence the cost model
341+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().LimitCostFactor )
342+ }
343+ // Multiply by cost factor - defaults to 1, but can be increased/decreased to influence the cost model
344+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().IndexLookupCostFactor )
309345 return p .PlanCostVer2 , nil
310346}
311347
@@ -363,8 +399,12 @@ func (p *PhysicalIndexMergeReader) GetPlanCostVer2(taskType property.TaskType, o
363399 // todo: refine the cost computation out from cost model.
364400 if p .PushedLimit != nil {
365401 p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , 0.99 )
402+ // Multiply by limit cost factor - defaults to 1, but can be increased/decreased to influence the cost model
403+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().LimitCostFactor )
366404 }
367405 p .PlanCostInit = true
406+ // Multiply by cost factor - defaults to 1, but can be increased/decreased to influence the cost model
407+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().IndexMergeCostFactor )
368408 return p .PlanCostVer2 , nil
369409}
370410
@@ -418,6 +458,8 @@ func (p *PhysicalSort) GetPlanCostVer2(taskType property.TaskType, option *optim
418458
419459 p .PlanCostVer2 = costusage .SumCostVer2 (childCost , sortCPUCost , sortMemCost , sortDiskCost )
420460 p .PlanCostInit = true
461+ // Multiply by cost factor - defaults to 1, but can be increased/decreased to influence the cost model
462+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().SortCostFactor )
421463 return p .PlanCostVer2 , nil
422464}
423465
@@ -453,6 +495,8 @@ func (p *PhysicalTopN) GetPlanCostVer2(taskType property.TaskType, option *optim
453495
454496 p .PlanCostVer2 = costusage .SumCostVer2 (childCost , topNCPUCost , topNMemCost )
455497 p .PlanCostInit = true
498+ // Multiply by cost factor - defaults to 1, but can be increased/decreased to influence the cost model
499+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().TopNCostFactor )
456500 return p .PlanCostVer2 , nil
457501}
458502
@@ -476,6 +520,8 @@ func (p *PhysicalStreamAgg) GetPlanCostVer2(taskType property.TaskType, option *
476520
477521 p .PlanCostVer2 = costusage .SumCostVer2 (childCost , aggCost , groupCost )
478522 p .PlanCostInit = true
523+ // Multiply by cost factor - defaults to 1, but can be increased/decreased to influence the cost model
524+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().StreamAggCostFactor )
479525 return p .PlanCostVer2 , nil
480526}
481527
@@ -508,6 +554,8 @@ func (p *PhysicalHashAgg) GetPlanCostVer2(taskType property.TaskType, option *op
508554
509555 p .PlanCostVer2 = costusage .SumCostVer2 (startCost , childCost , costusage .DivCostVer2 (costusage .SumCostVer2 (aggCost , groupCost , hashBuildCost , hashProbeCost ), concurrency ))
510556 p .PlanCostInit = true
557+ // Multiply by cost factor - defaults to 1, but can be increased/decreased to influence the cost model
558+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().HashAggCostFactor )
511559 return p .PlanCostVer2 , nil
512560}
513561
@@ -538,6 +586,8 @@ func (p *PhysicalMergeJoin) GetPlanCostVer2(taskType property.TaskType, option *
538586
539587 p .PlanCostVer2 = costusage .SumCostVer2 (leftChildCost , rightChildCost , filterCost , groupCost )
540588 p .PlanCostInit = true
589+ // Multiply by cost factor - defaults to 1, but can be increased/decreased to influence the cost model
590+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().MergeJoinCostFactor )
541591 return p .PlanCostVer2 , nil
542592}
543593
@@ -591,6 +641,8 @@ func (p *PhysicalHashJoin) GetPlanCostVer2(taskType property.TaskType, option *o
591641 costusage .DivCostVer2 (costusage .SumCostVer2 (probeFilterCost , probeHashCost ), tidbConcurrency ))
592642 }
593643 p .PlanCostInit = true
644+ // Multiply by cost factor - defaults to 1, but can be increased/decreased to influence the cost model
645+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().HashJoinCostFactor )
594646 return p .PlanCostVer2 , nil
595647}
596648
@@ -658,6 +710,8 @@ func (p *PhysicalIndexJoin) getIndexJoinCostVer2(taskType property.TaskType, opt
658710
659711 p .PlanCostVer2 = costusage .SumCostVer2 (startCost , buildChildCost , buildFilterCost , buildTaskCost , costusage .DivCostVer2 (costusage .SumCostVer2 (doubleReadCost , probeCost , probeFilterCost , hashTableCost ), probeConcurrency ))
660712 p .PlanCostInit = true
713+ // Multiply by cost factor - defaults to 1, but can be increased/decreased to influence the cost model
714+ p .PlanCostVer2 = costusage .MulCostVer2 (p .PlanCostVer2 , p .SCtx ().GetSessionVars ().IndexJoinCostFactor )
661715 return p .PlanCostVer2 , nil
662716}
663717
@@ -919,16 +973,6 @@ func getTableScanPenalty(p *PhysicalTableScan, rows float64) (rowPenalty float64
919973 if len (p .rangeInfo ) > 0 {
920974 return float64 (0 )
921975 }
922- var unsignedIntHandle bool
923- if p .Table .PKIsHandle {
924- if pkColInfo := p .Table .GetPkColInfo (); pkColInfo != nil {
925- unsignedIntHandle = mysql .HasUnsignedFlag (pkColInfo .GetFlag ())
926- }
927- }
928- hasFullRangeScan := ranger .HasFullRange (p .Ranges , unsignedIntHandle )
929- if ! hasFullRangeScan {
930- return float64 (0 )
931- }
932976
933977 sessionVars := p .SCtx ().GetSessionVars ()
934978 allowPreferRangeScan := sessionVars .GetAllowPreferRangeScan ()
@@ -956,7 +1000,7 @@ func getTableScanPenalty(p *PhysicalTableScan, rows float64) (rowPenalty float64
9561000 // penalty is applied to a full table scan (not range scan). This may also penalize a
9571001 // full table scan where USE/FORCE was applied to the primary key.
9581002 hasIndexForce := sessionVars .StmtCtx .GetIndexForce ()
959- shouldApplyPenalty := hasFullRangeScan && ( hasIndexForce || preferRangeScanCondition )
1003+ shouldApplyPenalty := hasIndexForce || preferRangeScanCondition
9601004 if shouldApplyPenalty {
9611005 // MySQL will increase the cost of table scan if FORCE index is used. TiDB takes this one
9621006 // step further - because we don't differentiate USE/FORCE - the added penalty applies to
0 commit comments