Skip to content

Commit 899e5cc

Browse files
authored
Planner: Do not allow cardinality to go below 1 (pingcap#58173)
close pingcap#47400
1 parent e7ebb75 commit 899e5cc

28 files changed

+193
-148
lines changed

pkg/planner/cardinality/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ go_library(
2525
"//pkg/planner/property",
2626
"//pkg/planner/util",
2727
"//pkg/planner/util/debugtrace",
28+
"//pkg/planner/util/fixcontrol",
2829
"//pkg/sessionctx",
2930
"//pkg/sessionctx/stmtctx",
3031
"//pkg/statistics",

pkg/planner/cardinality/row_count_column.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package cardinality
1717
import (
1818
"github.com/pingcap/errors"
1919
"github.com/pingcap/tidb/pkg/planner/util/debugtrace"
20+
"github.com/pingcap/tidb/pkg/planner/util/fixcontrol"
2021
"github.com/pingcap/tidb/pkg/sessionctx"
2122
"github.com/pingcap/tidb/pkg/statistics"
2223
"github.com/pingcap/tidb/pkg/types"
@@ -308,7 +309,17 @@ func GetColumnRowCount(sctx sessionctx.Context, c *statistics.Column, ranges []*
308309
}
309310
rowCount += cnt
310311
}
311-
rowCount = mathutil.Clamp(rowCount, 0, float64(realtimeRowCount))
312+
allowZeroEst := fixcontrol.GetBoolWithDefault(
313+
sctx.GetSessionVars().GetOptimizerFixControlMap(),
314+
fixcontrol.Fix47400,
315+
false,
316+
)
317+
if allowZeroEst {
318+
rowCount = mathutil.Clamp(rowCount, 0, float64(realtimeRowCount))
319+
} else {
320+
// Don't allow the final result to go below 1 row
321+
rowCount = mathutil.Clamp(rowCount, 1, float64(realtimeRowCount))
322+
}
312323
return rowCount, nil
313324
}
314325

pkg/planner/cardinality/row_count_index.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/pingcap/failpoint"
2525
"github.com/pingcap/tidb/pkg/kv"
2626
"github.com/pingcap/tidb/pkg/planner/util/debugtrace"
27+
"github.com/pingcap/tidb/pkg/planner/util/fixcontrol"
2728
"github.com/pingcap/tidb/pkg/sessionctx"
2829
"github.com/pingcap/tidb/pkg/sessionctx/stmtctx"
2930
"github.com/pingcap/tidb/pkg/statistics"
@@ -344,7 +345,17 @@ func getIndexRowCountForStatsV2(sctx sessionctx.Context, idx *statistics.Index,
344345
}
345346
totalCount += count
346347
}
347-
totalCount = mathutil.Clamp(totalCount, 0, float64(realtimeRowCount))
348+
allowZeroEst := fixcontrol.GetBoolWithDefault(
349+
sctx.GetSessionVars().GetOptimizerFixControlMap(),
350+
fixcontrol.Fix47400,
351+
false,
352+
)
353+
if allowZeroEst {
354+
totalCount = mathutil.Clamp(totalCount, 0, float64(realtimeRowCount))
355+
} else {
356+
// Don't allow the final result to go below 1 row
357+
totalCount = mathutil.Clamp(totalCount, 1, float64(realtimeRowCount))
358+
}
348359
return totalCount, nil
349360
}
350361

pkg/planner/cardinality/selectivity_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ func TestEstimationForUnknownValues(t *testing.T) {
234234
colID := table.Meta().Columns[0].ID
235235
count, err := cardinality.GetRowCountByColumnRanges(sctx, &statsTbl.HistColl, colID, getRange(30, 30))
236236
require.NoError(t, err)
237-
require.Equal(t, 0.2, count)
237+
require.Equal(t, 1.0, count)
238238

239239
count, err = cardinality.GetRowCountByColumnRanges(sctx, &statsTbl.HistColl, colID, getRange(9, 30))
240240
require.NoError(t, err)
@@ -263,7 +263,7 @@ func TestEstimationForUnknownValues(t *testing.T) {
263263
colID = table.Meta().Columns[0].ID
264264
count, err = cardinality.GetRowCountByColumnRanges(sctx, &statsTbl.HistColl, colID, getRange(1, 30))
265265
require.NoError(t, err)
266-
require.Equal(t, 0.0, count)
266+
require.Equal(t, 1.0, count)
267267

268268
testKit.MustExec("drop table t")
269269
testKit.MustExec("create table t(a int, b int, index idx(b))")
@@ -276,7 +276,7 @@ func TestEstimationForUnknownValues(t *testing.T) {
276276
colID = table.Meta().Columns[0].ID
277277
count, err = cardinality.GetRowCountByColumnRanges(sctx, &statsTbl.HistColl, colID, getRange(2, 2))
278278
require.NoError(t, err)
279-
require.Equal(t, 0.0, count)
279+
require.Equal(t, 1.0, count)
280280

281281
idxID = table.Meta().Indices[0].ID
282282
count, err = cardinality.GetRowCountByIndexRanges(sctx, &statsTbl.HistColl, idxID, getRange(2, 2))
@@ -422,8 +422,8 @@ func TestSelectivity(t *testing.T) {
422422
},
423423
{
424424
exprs: "a >= 1 and b > 1 and a < 2",
425-
selectivity: 0.01783264746,
426-
selectivityAfterIncrease: 0.01851851852,
425+
selectivity: 0.017832647462277088,
426+
selectivityAfterIncrease: 0.018518518518518517,
427427
},
428428
{
429429
exprs: "a >= 1 and c > 1 and a < 2",
@@ -442,13 +442,13 @@ func TestSelectivity(t *testing.T) {
442442
},
443443
{
444444
exprs: "b > 1",
445-
selectivity: 0.96296296296,
445+
selectivity: 0.9629629629629629,
446446
selectivityAfterIncrease: 1,
447447
},
448448
{
449449
exprs: "a > 1 and b < 2 and c > 3 and d < 4 and e > 5",
450-
selectivity: 0,
451-
selectivityAfterIncrease: 0,
450+
selectivity: 5.870830440255832e-05,
451+
selectivityAfterIncrease: 1.51329827770157e-05,
452452
},
453453
{
454454
exprs: longExpr,
@@ -1120,8 +1120,8 @@ func TestCrossValidationSelectivity(t *testing.T) {
11201120
require.NoError(t, h.DumpStatsDeltaToKV(true))
11211121
tk.MustExec("analyze table t")
11221122
tk.MustQuery("explain format = 'brief' select * from t where a = 1 and b > 0 and b < 1000 and c > 1000").Check(testkit.Rows(
1123-
"TableReader 0.00 root data:Selection",
1124-
"└─Selection 0.00 cop[tikv] gt(test.t.c, 1000)",
1123+
"TableReader 1.00 root data:Selection",
1124+
"└─Selection 1.00 cop[tikv] gt(test.t.c, 1000)",
11251125
" └─TableRangeScan 2.00 cop[tikv] table:t range:(1 0,1 1000), keep order:false"))
11261126
}
11271127

pkg/planner/cardinality/testdata/cardinality_suite_out.json

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
{
2525
"Start": 800,
2626
"End": 900,
27-
"Count": 752.004166655054
27+
"Count": 791.004166655054
2828
},
2929
{
3030
"Start": 900,
@@ -79,7 +79,7 @@
7979
{
8080
"Start": 800,
8181
"End": 1000,
82-
"Count": 1201.196869573942
82+
"Count": 1249.196869573942
8383
},
8484
{
8585
"Start": 900,
@@ -104,7 +104,7 @@
104104
{
105105
"Start": 200,
106106
"End": 400,
107-
"Count": 1211.5288209899081
107+
"Count": 1188.7788209899081
108108
},
109109
{
110110
"Start": 200,
@@ -2466,7 +2466,7 @@
24662466
},
24672467
{
24682468
"Name": "a",
2469-
"Result": 0
2469+
"Result": 1
24702470
}
24712471
]
24722472
},
@@ -2747,15 +2747,15 @@
27472747
},
27482748
{
27492749
"End estimate range": {
2750-
"RowCount": 0,
2750+
"RowCount": 1,
27512751
"Type": "Range"
27522752
}
27532753
}
27542754
]
27552755
},
27562756
{
27572757
"Name": "iab",
2758-
"Result": 0
2758+
"Result": 1
27592759
}
27602760
]
27612761
},
@@ -3307,11 +3307,11 @@
33073307
"Expressions": [
33083308
"lt(test.t.a, -1500)"
33093309
],
3310-
"Selectivity": 0,
3310+
"Selectivity": 0.0003246753246753247,
33113311
"partial cover": false
33123312
},
33133313
{
3314-
"Result": 0
3314+
"Result": 2.1082813290605499e-7
33153315
}
33163316
]
33173317
}
@@ -3740,7 +3740,7 @@
37403740
},
37413741
{
37423742
"Name": "iab",
3743-
"Result": 0
3743+
"Result": 1
37443744
}
37453745
]
37463746
},
@@ -3867,11 +3867,11 @@
38673867
"Expressions": [
38683868
"lt(test.t.a, -1500)"
38693869
],
3870-
"Selectivity": 0,
3870+
"Selectivity": 0.0003246753246753247,
38713871
"partial cover": false
38723872
},
38733873
{
3874-
"Result": 0
3874+
"Result": 1.9066503965832828e-7
38753875
}
38763876
]
38773877
}

pkg/planner/core/casetest/cbotest/testdata/analyze_suite_out.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,13 +364,13 @@
364364
"└─TableRowIDScan(Probe) 2.00 cop[tikv] table:t keep order:false"
365365
],
366366
[
367-
"TableReader 0.00 root data:Selection",
368-
"└─Selection 0.00 cop[tikv] eq(test.t.b, 1)",
367+
"TableReader 1.00 root data:Selection",
368+
"└─Selection 1.00 cop[tikv] eq(test.t.b, 1)",
369369
" └─TableFullScan 2.00 cop[tikv] table:t keep order:false"
370370
],
371371
[
372-
"TableReader 0.00 root data:Selection",
373-
"└─Selection 0.00 cop[tikv] lt(test.t.b, 1)",
372+
"TableReader 1.00 root data:Selection",
373+
"└─Selection 1.00 cop[tikv] lt(test.t.b, 1)",
374374
" └─TableFullScan 2.00 cop[tikv] table:t keep order:false"
375375
]
376376
]

pkg/planner/core/casetest/index/testdata/integration_suite_out.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,8 @@
174174
{
175175
"SQL": "select * from t1 where t1.a = 1 and t1.b < \"333\"",
176176
"Plan": [
177-
"TableReader 0.82 root data:TableRangeScan",
178-
"└─TableRangeScan 0.82 cop[tikv] table:t1 range:[1 -inf,1 \"333\"), keep order:false"
177+
"TableReader 1.00 root data:TableRangeScan",
178+
"└─TableRangeScan 1.00 cop[tikv] table:t1 range:[1 -inf,1 \"333\"), keep order:false"
179179
],
180180
"Res": [
181181
"1 111 1.1000000000 11"

pkg/planner/core/casetest/partition/testdata/integration_partition_suite_out.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@
709709
"└─IndexRangeScan 1.00 cop[tikv] table:t, index:b(b) range:[1,1], keep order:false"
710710
],
711711
"StaticPlan": [
712-
"PartitionUnion 1.00 root ",
712+
"PartitionUnion 3.00 root ",
713713
"├─IndexReader 1.00 root index:IndexRangeScan",
714714
"│ └─IndexRangeScan 1.00 cop[tikv] table:t, partition:P0, index:b(b) range:[1,1], keep order:false",
715715
"├─IndexReader 1.00 root index:IndexRangeScan",
@@ -725,7 +725,7 @@
725725
"└─IndexRangeScan 1.00 cop[tikv] table:t, index:b(b) range:[2,2], keep order:false"
726726
],
727727
"StaticPlan": [
728-
"PartitionUnion 1.00 root ",
728+
"PartitionUnion 3.00 root ",
729729
"├─IndexReader 1.00 root index:IndexRangeScan",
730730
"│ └─IndexRangeScan 1.00 cop[tikv] table:t, partition:P0, index:b(b) range:[2,2], keep order:false",
731731
"├─IndexReader 1.00 root index:IndexRangeScan",
@@ -741,7 +741,7 @@
741741
"└─IndexRangeScan 2.00 cop[tikv] table:t, index:b(b) range:[1,2], keep order:false"
742742
],
743743
"StaticPlan": [
744-
"PartitionUnion 2.00 root ",
744+
"PartitionUnion 3.00 root ",
745745
"├─IndexReader 1.00 root index:IndexRangeScan",
746746
"│ └─IndexRangeScan 1.00 cop[tikv] table:t, partition:P0, index:b(b) range:[1,2], keep order:false",
747747
"├─IndexReader 1.00 root index:IndexRangeScan",
@@ -757,7 +757,7 @@
757757
"└─IndexRangeScan 2.00 cop[tikv] table:t, index:b(b) range:[2,2], [3,3], [4,4], keep order:false"
758758
],
759759
"StaticPlan": [
760-
"PartitionUnion 2.00 root ",
760+
"PartitionUnion 3.00 root ",
761761
"├─IndexReader 1.00 root index:IndexRangeScan",
762762
"│ └─IndexRangeScan 1.00 cop[tikv] table:t, partition:P0, index:b(b) range:[2,2], [3,3], [4,4], keep order:false",
763763
"├─IndexReader 1.00 root index:IndexRangeScan",
@@ -773,7 +773,7 @@
773773
"└─IndexRangeScan 2.00 cop[tikv] table:t, index:b(b) range:[2,2], [3,3], keep order:false"
774774
],
775775
"StaticPlan": [
776-
"PartitionUnion 2.00 root ",
776+
"PartitionUnion 3.00 root ",
777777
"├─IndexReader 1.00 root index:IndexRangeScan",
778778
"│ └─IndexRangeScan 1.00 cop[tikv] table:t, partition:P0, index:b(b) range:[2,2], [3,3], keep order:false",
779779
"├─IndexReader 1.00 root index:IndexRangeScan",
@@ -854,7 +854,7 @@
854854
"└─IndexRangeScan 1.00 cop[tikv] table:t, index:b(b) range:[1,1], keep order:false"
855855
],
856856
"StaticPlan": [
857-
"PartitionUnion 1.00 root ",
857+
"PartitionUnion 2.00 root ",
858858
"├─IndexReader 1.00 root index:IndexRangeScan",
859859
"│ └─IndexRangeScan 1.00 cop[tikv] table:t, partition:P0, index:b(b) range:[1,1], keep order:false",
860860
"└─IndexReader 1.00 root index:IndexRangeScan",

pkg/planner/core/casetest/planstats/testdata/plan_stats_suite_out.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,10 @@
116116
{
117117
"Query": "explain format = brief select * from t join tp where tp.a = 10 and t.b = tp.c",
118118
"Result": [
119-
"Projection 0.00 root test.t.a, test.t.b, test.t.c, test.tp.a, test.tp.b, test.tp.c",
120-
"└─HashJoin 0.00 root inner join, equal:[eq(test.tp.c, test.t.b)]",
121-
" ├─TableReader(Build) 0.00 root partition:p1 data:Selection",
122-
" │ └─Selection 0.00 cop[tikv] eq(test.tp.a, 10), not(isnull(test.tp.c))",
119+
"Projection 1.00 root test.t.a, test.t.b, test.t.c, test.tp.a, test.tp.b, test.tp.c",
120+
"└─HashJoin 1.00 root inner join, equal:[eq(test.tp.c, test.t.b)]",
121+
" ├─TableReader(Build) 1.00 root partition:p1 data:Selection",
122+
" │ └─Selection 1.00 cop[tikv] eq(test.tp.a, 10), not(isnull(test.tp.c))",
123123
" │ └─TableFullScan 6.00 cop[tikv] table:tp keep order:false, stats:partial[ic:allEvicted, c:allEvicted]",
124124
" └─TableReader(Probe) 3.00 root data:Selection",
125125
" └─Selection 3.00 cop[tikv] not(isnull(test.t.b))",

pkg/planner/core/casetest/testdata/integration_suite_out.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -286,25 +286,25 @@
286286
"SQL": "explain format = 'verbose' select count(*) from t3 where b = 0",
287287
"Plan": [
288288
"StreamAgg_10 1.00 64.98 root funcs:count(1)->Column#4",
289-
"└─IndexReader_15 0.00 15.08 root index:IndexRangeScan_14",
290-
" └─IndexRangeScan_14 0.00 162.80 cop[tikv] table:t3, index:c(b) range:[0,0], keep order:false"
289+
"└─IndexReader_15 1.00 15.08 root index:IndexRangeScan_14",
290+
" └─IndexRangeScan_14 1.00 162.80 cop[tikv] table:t3, index:c(b) range:[0,0], keep order:false"
291291
]
292292
},
293293
{
294294
"SQL": "explain format = 'verbose' select /*+ use_index(t3, c) */ count(a) from t3 where b = 0",
295295
"Plan": [
296296
"StreamAgg_10 1.00 2001.63 root funcs:count(test.t3.a)->Column#4",
297-
"└─IndexLookUp_17 0.00 1951.73 root ",
298-
" ├─IndexRangeScan_15(Build) 0.00 203.50 cop[tikv] table:t3, index:c(b) range:[0,0], keep order:false",
299-
" └─TableRowIDScan_16(Probe) 0.00 227.31 cop[tikv] table:t3 keep order:false"
297+
"└─IndexLookUp_17 1.00 1951.73 root ",
298+
" ├─IndexRangeScan_15(Build) 1.00 203.50 cop[tikv] table:t3, index:c(b) range:[0,0], keep order:false",
299+
" └─TableRowIDScan_16(Probe) 1.00 227.31 cop[tikv] table:t3 keep order:false"
300300
]
301301
},
302302
{
303303
"SQL": "explain format = 'verbose' select count(*) from t2 where a = 0",
304304
"Plan": [
305305
"StreamAgg_12 1.00 109.57 root funcs:count(1)->Column#4",
306-
"└─TableReader_20 0.00 59.67 root data:Selection_19",
307-
" └─Selection_19 0.00 831.62 cop[tikv] eq(test.t2.a, 0)",
306+
"└─TableReader_20 1.00 59.67 root data:Selection_19",
307+
" └─Selection_19 1.00 831.62 cop[tikv] eq(test.t2.a, 0)",
308308
" └─TableFullScan_18 3.00 681.92 cop[tikv] table:t2 keep order:false"
309309
]
310310
},

0 commit comments

Comments
 (0)