@@ -243,20 +243,79 @@ type BucketFeedback struct {
243
243
upper * types.Datum // The upper bound of the new bucket.
244
244
}
245
245
246
+ // outOfRange checks if the `val` is between `min` and `max`.
247
+ func outOfRange (sc * stmtctx.StatementContext , min , max , val * types.Datum ) (int , error ) {
248
+ result , err := val .CompareDatum (sc , min )
249
+ if err != nil {
250
+ return 0 , err
251
+ }
252
+ if result < 0 {
253
+ return result , nil
254
+ }
255
+ result , err = val .CompareDatum (sc , max )
256
+ if err != nil {
257
+ return 0 , err
258
+ }
259
+ if result > 0 {
260
+ return result , nil
261
+ }
262
+ return 0 , nil
263
+ }
264
+
265
+ // adjustFeedbackBoundaries adjust the feedback boundaries according to the `min` and `max`.
266
+ // If the feedback has no intersection with `min` and `max`, we could just skip this feedback.
267
+ func (f * feedback ) adjustFeedbackBoundaries (sc * stmtctx.StatementContext , min , max * types.Datum ) (bool , error ) {
268
+ result , err := outOfRange (sc , min , max , f .lower )
269
+ if err != nil {
270
+ return false , err
271
+ }
272
+ if result > 0 {
273
+ return true , nil
274
+ }
275
+ if result < 0 {
276
+ f .lower = min
277
+ }
278
+ result , err = outOfRange (sc , min , max , f .upper )
279
+ if err != nil {
280
+ return false , err
281
+ }
282
+ if result < 0 {
283
+ return true , nil
284
+ }
285
+ if result > 0 {
286
+ f .upper = max
287
+ }
288
+ return false , nil
289
+ }
290
+
246
291
// buildBucketFeedback build the feedback for each bucket from the histogram feedback.
247
292
func buildBucketFeedback (h * Histogram , feedback * QueryFeedback ) (map [int ]* BucketFeedback , int ) {
248
293
bktID2FB := make (map [int ]* BucketFeedback )
294
+ if len (feedback .feedback ) == 0 {
295
+ return bktID2FB , 0
296
+ }
249
297
total := 0
250
- for _ , ran := range feedback .feedback {
251
- idx , _ := h .Bounds .LowerBound (0 , ran .lower )
298
+ sc := & stmtctx.StatementContext {TimeZone : time .UTC }
299
+ kind := feedback .feedback [0 ].lower .Kind ()
300
+ min , max := getMinValue (kind , h .tp ), getMaxValue (kind , h .tp )
301
+ for _ , fb := range feedback .feedback {
302
+ skip , err := fb .adjustFeedbackBoundaries (sc , & min , & max )
303
+ if err != nil {
304
+ log .Debugf ("adjust feedback boundaries failed, err: %v" , errors .ErrorStack (err ))
305
+ continue
306
+ }
307
+ if skip {
308
+ continue
309
+ }
310
+ idx , _ := h .Bounds .LowerBound (0 , fb .lower )
252
311
bktIdx := 0
253
312
// The last bucket also stores the feedback that falls outside the upper bound.
254
313
if idx >= h .Bounds .NumRows ()- 2 {
255
314
bktIdx = h .Len () - 1
256
315
} else {
257
316
bktIdx = idx / 2
258
317
// Make sure that this feedback lies within the bucket.
259
- if chunk .Compare (h .Bounds .GetRow (2 * bktIdx + 1 ), 0 , ran .upper ) < 0 {
318
+ if chunk .Compare (h .Bounds .GetRow (2 * bktIdx + 1 ), 0 , fb .upper ) < 0 {
260
319
continue
261
320
}
262
321
}
@@ -266,23 +325,23 @@ func buildBucketFeedback(h *Histogram, feedback *QueryFeedback) (map[int]*Bucket
266
325
bkt = & BucketFeedback {lower : h .GetLower (bktIdx ), upper : h .GetUpper (bktIdx )}
267
326
bktID2FB [bktIdx ] = bkt
268
327
}
269
- bkt .feedback = append (bkt .feedback , ran )
328
+ bkt .feedback = append (bkt .feedback , fb )
270
329
// Update the bound if necessary.
271
- res , err := bkt .lower .CompareDatum (nil , ran .lower )
330
+ res , err := bkt .lower .CompareDatum (nil , fb .lower )
272
331
if err != nil {
273
- log .Debugf ("compare datum %v with %v failed, err: %v" , bkt .lower , ran .lower , errors .ErrorStack (err ))
332
+ log .Debugf ("compare datum %v with %v failed, err: %v" , bkt .lower , fb .lower , errors .ErrorStack (err ))
274
333
continue
275
334
}
276
335
if res > 0 {
277
- bkt .lower = ran .lower
336
+ bkt .lower = fb .lower
278
337
}
279
- res , err = bkt .upper .CompareDatum (nil , ran .upper )
338
+ res , err = bkt .upper .CompareDatum (nil , fb .upper )
280
339
if err != nil {
281
- log .Debugf ("compare datum %v with %v failed, err: %v" , bkt .upper , ran .upper , errors .ErrorStack (err ))
340
+ log .Debugf ("compare datum %v with %v failed, err: %v" , bkt .upper , fb .upper , errors .ErrorStack (err ))
282
341
continue
283
342
}
284
343
if res < 0 {
285
- bkt .upper = ran .upper
344
+ bkt .upper = fb .upper
286
345
}
287
346
}
288
347
return bktID2FB , total
@@ -528,7 +587,12 @@ func splitBuckets(h *Histogram, feedback *QueryFeedback) ([]bucket, []bool, int6
528
587
func UpdateHistogram (h * Histogram , feedback * QueryFeedback ) * Histogram {
529
588
buckets , isNewBuckets , totalCount := splitBuckets (h , feedback )
530
589
buckets = mergeBuckets (buckets , isNewBuckets , float64 (totalCount ))
531
- return buildNewHistogram (h , buckets )
590
+ hist := buildNewHistogram (h , buckets )
591
+ // Update the NDV of primary key column.
592
+ if feedback .tp == pkType {
593
+ hist .NDV = int64 (hist .totalRowCount ())
594
+ }
595
+ return hist
532
596
}
533
597
534
598
// UpdateCMSketch updates the CMSketch by feedback.
@@ -1077,13 +1141,13 @@ func supportColumnType(k byte) bool {
1077
1141
func getMaxValue (k byte , ft * types.FieldType ) (max types.Datum ) {
1078
1142
switch k {
1079
1143
case types .KindInt64 :
1080
- max .SetInt64 (math . MaxInt64 )
1144
+ max .SetInt64 (types . SignedUpperBound [ ft . Tp ] )
1081
1145
case types .KindUint64 :
1082
- max .SetUint64 (math . MaxUint64 )
1146
+ max .SetUint64 (types . UnsignedUpperBound [ ft . Tp ] )
1083
1147
case types .KindFloat32 :
1084
- max .SetFloat32 (math . MaxFloat32 )
1148
+ max .SetFloat32 (float32 ( types . GetMaxFloat ( ft . Flen , ft . Decimal )) )
1085
1149
case types .KindFloat64 :
1086
- max .SetFloat64 (math . MaxFloat64 )
1150
+ max .SetFloat64 (types . GetMaxFloat ( ft . Flen , ft . Decimal ) )
1087
1151
case types .KindString , types .KindBytes :
1088
1152
val := types .MaxValueDatum ()
1089
1153
bytes , err := codec .EncodeKey (nil , nil , val )
@@ -1093,7 +1157,7 @@ func getMaxValue(k byte, ft *types.FieldType) (max types.Datum) {
1093
1157
}
1094
1158
max .SetBytes (bytes )
1095
1159
case types .KindMysqlDecimal :
1096
- max .SetMysqlDecimal (types .NewMaxOrMinDec (false , mysql . MaxDecimalWidth , 0 ))
1160
+ max .SetMysqlDecimal (types .NewMaxOrMinDec (false , ft . Flen , ft . Decimal ))
1097
1161
case types .KindMysqlDuration :
1098
1162
max .SetMysqlDuration (types.Duration {Duration : math .MaxInt64 })
1099
1163
case types .KindMysqlTime :
@@ -1109,13 +1173,13 @@ func getMaxValue(k byte, ft *types.FieldType) (max types.Datum) {
1109
1173
func getMinValue (k byte , ft * types.FieldType ) (min types.Datum ) {
1110
1174
switch k {
1111
1175
case types .KindInt64 :
1112
- min .SetInt64 (math . MinInt64 )
1176
+ min .SetInt64 (types . SignedLowerBound [ ft . Tp ] )
1113
1177
case types .KindUint64 :
1114
1178
min .SetUint64 (0 )
1115
1179
case types .KindFloat32 :
1116
- min .SetFloat32 (- math . MaxFloat32 )
1180
+ min .SetFloat32 (float32 ( - types . GetMaxFloat ( ft . Flen , ft . Decimal )) )
1117
1181
case types .KindFloat64 :
1118
- min .SetFloat64 (- math . MaxFloat64 )
1182
+ min .SetFloat64 (- types . GetMaxFloat ( ft . Flen , ft . Decimal ) )
1119
1183
case types .KindString , types .KindBytes :
1120
1184
val := types .MinNotNullDatum ()
1121
1185
bytes , err := codec .EncodeKey (nil , nil , val )
@@ -1125,7 +1189,7 @@ func getMinValue(k byte, ft *types.FieldType) (min types.Datum) {
1125
1189
}
1126
1190
min .SetBytes (bytes )
1127
1191
case types .KindMysqlDecimal :
1128
- min .SetMysqlDecimal (types .NewMaxOrMinDec (true , mysql . MaxDecimalWidth , 0 ))
1192
+ min .SetMysqlDecimal (types .NewMaxOrMinDec (true , ft . Flen , ft . Decimal ))
1129
1193
case types .KindMysqlDuration :
1130
1194
min .SetMysqlDuration (types.Duration {Duration : math .MinInt64 })
1131
1195
case types .KindMysqlTime :
0 commit comments