mirror of
https://github.com/go-gitea/gitea
synced 2024-09-18 01:36:08 +00:00
116 lines
3.0 KiB
Go
116 lines
3.0 KiB
Go
|
// 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
|
|||
|
}
|