// Copyright 2015 PingCAP, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // See the License for the specific language governing permissions and // limitations under the License. package plan import ( "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/parser/opcode" ) const ( rateFull float64 = 1 rateEqual float64 = 0.01 rateNotEqual float64 = 0.99 rateBetween float64 = 0.1 rateGreaterOrLess float64 = 0.33 rateIsFalse float64 = 0.1 rateIsNull float64 = 0.1 rateLike float64 = 0.1 ) // guesstimateFilterRate guesstimates the filter rate for an expression. // For example: a table has 100 rows, after filter expression 'a between 0 and 9', // 10 rows returned, then the filter rate is '0.1'. // It only depends on the expression type, not the expression value. // The expr parameter should contain only one column name. func guesstimateFilterRate(expr ast.ExprNode) float64 { switch x := expr.(type) { case *ast.BetweenExpr: return rateBetween case *ast.BinaryOperationExpr: return guesstimateBinop(x) case *ast.ColumnNameExpr: return rateFull case *ast.IsNullExpr: return guesstimateIsNull(x) case *ast.IsTruthExpr: return guesstimateIsTrue(x) case *ast.ParenthesesExpr: return guesstimateFilterRate(x.Expr) case *ast.PatternInExpr: return guesstimatePatternIn(x) case *ast.PatternLikeExpr: return guesstimatePatternLike(x) } return rateFull } func guesstimateBinop(expr *ast.BinaryOperationExpr) float64 { switch expr.Op { case opcode.AndAnd: // P(A and B) = P(A) * P(B) return guesstimateFilterRate(expr.L) * guesstimateFilterRate(expr.R) case opcode.OrOr: // P(A or B) = P(A) + P(B) – P(A and B) rateL := guesstimateFilterRate(expr.L) rateR := guesstimateFilterRate(expr.R) return rateL + rateR - rateL*rateR case opcode.EQ: return rateEqual case opcode.GT, opcode.GE, opcode.LT, opcode.LE: return rateGreaterOrLess case opcode.NE: return rateNotEqual } return rateFull } func guesstimateIsNull(expr *ast.IsNullExpr) float64 { if expr.Not { return rateFull - rateIsNull } return rateIsNull } func guesstimateIsTrue(expr *ast.IsTruthExpr) float64 { if expr.True == 0 { if expr.Not { return rateFull - rateIsFalse } return rateIsFalse } if expr.Not { return rateIsFalse + rateIsNull } return rateFull - rateIsFalse - rateIsNull } func guesstimatePatternIn(expr *ast.PatternInExpr) float64 { if len(expr.List) > 0 { rate := rateEqual * float64(len(expr.List)) if expr.Not { return rateFull - rate } return rate } return rateFull } func guesstimatePatternLike(expr *ast.PatternLikeExpr) float64 { if expr.Not { return rateFull - rateLike } return rateLike }