@@ -1032,6 +1032,10 @@ func (p *PhysicalTopN) pushTopNDownToDynamicPartition(copTsk *copTask) (task, bo
1032
1032
return true
1033
1033
}
1034
1034
var (
1035
+ selOnIdxScan * PhysicalSelection
1036
+ selOnTblScan * PhysicalSelection
1037
+ selSelectivity float64
1038
+
1035
1039
idxScan * PhysicalIndexScan
1036
1040
tblScan * PhysicalTableScan
1037
1041
tblInfo * model.TableInfo
@@ -1044,6 +1048,7 @@ func (p *PhysicalTopN) pushTopNDownToDynamicPartition(copTsk *copTask) (task, bo
1044
1048
}
1045
1049
finalIdxScanPlan := copTsk .indexPlan
1046
1050
for len (finalIdxScanPlan .Children ()) > 0 && finalIdxScanPlan .Children ()[0 ] != nil {
1051
+ selOnIdxScan , _ = finalIdxScanPlan .(* PhysicalSelection )
1047
1052
finalIdxScanPlan = finalIdxScanPlan .Children ()[0 ]
1048
1053
}
1049
1054
idxScan = finalIdxScanPlan .(* PhysicalIndexScan )
@@ -1056,12 +1061,21 @@ func (p *PhysicalTopN) pushTopNDownToDynamicPartition(copTsk *copTask) (task, bo
1056
1061
}
1057
1062
finalTblScanPlan := copTsk .tablePlan
1058
1063
for len (finalTblScanPlan .Children ()) > 0 {
1064
+ selOnTblScan , _ = finalTblScanPlan .(* PhysicalSelection )
1059
1065
finalTblScanPlan = finalTblScanPlan .Children ()[0 ]
1060
1066
}
1061
1067
tblScan = finalTblScanPlan .(* PhysicalTableScan )
1062
1068
tblInfo = tblScan .Table
1063
1069
}
1064
1070
1071
+ // Note that we only need to care about one Selection at most.
1072
+ if selOnIdxScan != nil && idxScan .statsInfo ().RowCount > 0 {
1073
+ selSelectivity = selOnIdxScan .statsInfo ().RowCount / idxScan .statsInfo ().RowCount
1074
+ }
1075
+ if idxScan == nil && selOnTblScan != nil && tblScan .statsInfo ().RowCount > 0 {
1076
+ selSelectivity = selOnTblScan .statsInfo ().RowCount / tblScan .statsInfo ().RowCount
1077
+ }
1078
+
1065
1079
pi := tblInfo .GetPartitionInfo ()
1066
1080
if pi == nil {
1067
1081
return nil , false
@@ -1083,6 +1097,17 @@ func (p *PhysicalTopN) pushTopNDownToDynamicPartition(copTsk *copTask) (task, bo
1083
1097
}.Init (p .SCtx (), stats , p .SelectBlockOffset ())
1084
1098
pushedLimit .SetSchema (copTsk .indexPlan .Schema ())
1085
1099
copTsk = attachPlan2Task (pushedLimit , copTsk ).(* copTask )
1100
+
1101
+ // A similar but simplified logic compared the ExpectedCnt handling logic in getOriginalPhysicalIndexScan.
1102
+ child := pushedLimit .Children ()[0 ]
1103
+ // The row count of the direct child of Limit should be adjusted to be no larger than the Limit.Count.
1104
+ child .SetStats (child .statsInfo ().ScaleByExpectCnt (float64 (newCount )))
1105
+ // The Limit->Selection->IndexScan case:
1106
+ // adjust the row count of IndexScan according to the selectivity of the Selection.
1107
+ if selSelectivity > 0 && selSelectivity < 1 {
1108
+ scaledRowCount := child .Stats ().RowCount / selSelectivity
1109
+ idxScan .SetStats (idxScan .Stats ().ScaleByExpectCnt (scaledRowCount ))
1110
+ }
1086
1111
} else if copTsk .indexPlan == nil {
1087
1112
if tblScan .HandleCols == nil {
1088
1113
return nil , false
@@ -1111,6 +1136,17 @@ func (p *PhysicalTopN) pushTopNDownToDynamicPartition(copTsk *copTask) (task, bo
1111
1136
}.Init (p .SCtx (), stats , p .SelectBlockOffset ())
1112
1137
pushedLimit .SetSchema (copTsk .tablePlan .Schema ())
1113
1138
copTsk = attachPlan2Task (pushedLimit , copTsk ).(* copTask )
1139
+
1140
+ // A similar but simplified logic compared the ExpectedCnt handling logic in getOriginalPhysicalTableScan.
1141
+ child := pushedLimit .Children ()[0 ]
1142
+ // The row count of the direct child of Limit should be adjusted to be no larger than the Limit.Count.
1143
+ child .SetStats (child .statsInfo ().ScaleByExpectCnt (float64 (newCount )))
1144
+ // The Limit->Selection->TableScan case:
1145
+ // adjust the row count of IndexScan according to the selectivity of the Selection.
1146
+ if selSelectivity > 0 && selSelectivity < 1 {
1147
+ scaledRowCount := child .Stats ().RowCount / selSelectivity
1148
+ tblScan .SetStats (tblScan .Stats ().ScaleByExpectCnt (scaledRowCount ))
1149
+ }
1114
1150
} else {
1115
1151
return nil , false
1116
1152
}
0 commit comments