Esempio n. 1
0
func NewExpressionSargable(indexExpression ast.Expression) *ExpressionSargable {
	return &ExpressionSargable{
		indexExpression:    indexExpression,
		equivalenceChecker: ast.NewExpressionEquivalenceChecker(ast.ExpressionList{indexExpression}),
		constantChecker:    ast.NewExpressionFunctionalDependencyCheckerFull(ast.ExpressionList{}),
		sargable:           false,
		scanRanges:         make(plan.ScanRanges, 0),
	}
}
Esempio n. 2
0
func CanFastCountIndex(index catalog.CountIndex, bucket string, resultExprList ast.ResultExpressionList) ast.Expression {

	// convert the index key to formal notation
	indexKeyFormal, err := IndexKeyInFormalNotation(index.Key(), bucket)
	if err != nil {
		return nil
	}

	deps := ast.ExpressionList{indexKeyFormal[0]}
	clog.To(planner.CHANNEL, "index deps are: %v", deps)
	depChecker := ast.NewExpressionFunctionalDependencyCheckerFull(deps)

	// start looking at the projection
	for _, resultExpr := range resultExprList {

		// cannot be *
		if resultExpr.Star {
			return nil
		}

		switch resultExpr := resultExpr.Expr.(type) {
		case *ast.FunctionCallCount:
			// aggregates all take 1 operand
			operands := resultExpr.GetOperands()
			if len(operands) < 1 {
				return nil
			}
			aggOperand := operands[0]
			// must NOT be *
			if aggOperand.Star {
				return nil
			}

			// look at dependencies inside this operand
			_, err := depChecker.Visit(aggOperand.Expr)
			if err != nil {
				return nil
			}
		default:
			return nil
		}
	}

	// if we made it this far, can do fast count on bucket
	return indexKeyFormal[0]
}
Esempio n. 3
0
func CanIUseThisIndexForThisProjectionNoWhereNoGroupClause(index catalog.RangeIndex, resultExprList ast.ResultExpressionList, bucket string) (bool, plan.ScanRanges, ast.Expression, error) {

	// convert the index key to formal notation
	indexKeyFormal, err := IndexKeyInFormalNotation(index.Key(), bucket)
	if err != nil {
		return false, nil, nil, err
	}

	// FIXME only looking at first element in key right now
	deps := ast.ExpressionList{indexKeyFormal[0]}
	clog.To(planner.CHANNEL, "index deps are: %v", deps)
	depChecker := ast.NewExpressionFunctionalDependencyCheckerFull(deps)

	// start looking at the projection
	allAggregateFunctionsMin := true
	for _, resultExpr := range resultExprList {

		// presence of * means we cannot use index on field, must see all (for this particular optimization)
		if resultExpr.Star {
			return false, nil, nil, nil
		}

		switch expr := resultExpr.Expr.(type) {
		case ast.AggregateFunctionCallExpression:
			_, isMin := expr.(*ast.FunctionCallMin)
			if !isMin {
				clog.To(planner.CHANNEL, "projection not MIN")
				allAggregateFunctionsMin = false
			}
			// aggregates all take 1 operand
			operands := expr.GetOperands()
			if len(operands) < 1 {
				return false, nil, nil, nil
			}
			aggOperand := operands[0]
			// preence of * means we cannot use this index, must see all (for this particular optimization)
			if aggOperand.Star {
				return false, nil, nil, nil
			}
			// look at dependencies inside this operand
			_, err := depChecker.Visit(aggOperand.Expr)
			if err != nil {
				return false, nil, nil, nil
			}
		default:
			// all expressions must be aggregates for this particular optimization
			return false, nil, nil, nil
		}
	}

	// if we made it this far, we can in fact use the index
	// doing a scan of all non-eliminatable items (non-NULL, non-MISSING)
	dummyOp := ast.NewIsNotNullOperator(indexKeyFormal[0])
	es := NewExpressionSargable(indexKeyFormal[0])
	dummyOp.Accept(es)
	if es.IsSargable() {
		ranges := es.ScanRanges()
		if allAggregateFunctionsMin {
			for _, r := range ranges {
				r.Limit = 1
			}
		}
		return true, ranges, nil, nil
	}
	clog.Error(fmt.Errorf("expected this to never happen"))

	// cannot use this index
	return false, nil, nil, nil
}
Esempio n. 4
0
func DoesIndexCoverStatement(index catalog.RangeIndex, stmt *ast.SelectStatement) bool {

	if stmt.From.Over != nil {
		// index cannot cover queries containing OVER right now
		return false
	}

	// convert the index key to formal notation
	indexKeyFormal, err := IndexKeyInFormalNotation(index.Key(), stmt.From.As)
	if err != nil {
		return false
	}

	deps := ast.ExpressionList{}
	for _, indexKey := range indexKeyFormal {
		deps = append(deps, indexKey)
	}
	clog.To(planner.CHANNEL, "index deps are: %v", deps)
	depChecker := ast.NewExpressionFunctionalDependencyCheckerFull(deps)

	// first check the projection
	for _, resultExpr := range stmt.Select {
		if resultExpr.Star == true || resultExpr.Expr == nil {
			// currently cannot cover *
			return false
		}

		_, err := depChecker.Visit(resultExpr.Expr)
		if err != nil {
			return false
		}
	}

	if stmt.Where != nil {
		_, err = depChecker.Visit(stmt.Where)
		if err != nil {
			return false
		}
	}

	if stmt.GroupBy != nil {
		for _, groupExpr := range stmt.GroupBy {
			_, err = depChecker.Visit(groupExpr)
			if err != nil {
				return false
			}
		}

		if stmt.Having != nil {
			_, err = depChecker.Visit(stmt.Having)
			if err != nil {
				return false
			}
		}
	}

	if stmt.OrderBy != nil {
		for _, orderExpr := range stmt.OrderBy {
			_, err = depChecker.Visit(orderExpr.Expr)
			if err != nil {
				return false
			}
		}
	}

	// if we go this far it is covered
	return true
}