mirror of
https://github.com/postgres/postgres.git
synced 2025-04-21 12:05:57 +03:00
Do ScalarArrayOp estimation correctly when array is a stable expression.
Most estimation functions apply estimate_expression_value to see if they can reduce an expression to a constant; the key difference is that it allows evaluation of stable as well as immutable functions in hopes of ending up with a simple Const node. scalararraysel didn't get the memo though, and neither did gincost_opexpr/gincost_scalararrayopexpr. Fix that, and remove a now-unnecessary estimate_expression_value step in the subsidiary function scalararraysel_containment. Per complaint from Alexey Klyukin. Back-patch to 9.3. The problem goes back further, but I'm hesitant to change estimation behavior in long-stable release branches.
This commit is contained in:
parent
5a7e75849c
commit
e8655a77f3
@ -68,11 +68,13 @@ static int float_compare_desc(const void *key1, const void *key2);
|
|||||||
* scalararraysel_containment
|
* scalararraysel_containment
|
||||||
* Estimate selectivity of ScalarArrayOpExpr via array containment.
|
* Estimate selectivity of ScalarArrayOpExpr via array containment.
|
||||||
*
|
*
|
||||||
* scalararraysel() has already verified that the operator of a
|
* If we have const =/<> ANY/ALL (array_var) then we can estimate the
|
||||||
* ScalarArrayOpExpr is the array element type's default equality or
|
* selectivity as though this were an array containment operator,
|
||||||
* inequality operator. If we have const =/<> ANY/ALL (array_var)
|
* array_var op ARRAY[const].
|
||||||
* then we can estimate the selectivity as though this were an array
|
*
|
||||||
* containment operator, array_var op ARRAY[const].
|
* scalararraysel() has already verified that the ScalarArrayOpExpr's operator
|
||||||
|
* is the array element type's default equality or inequality operator, and
|
||||||
|
* has aggressively simplified both inputs to constants.
|
||||||
*
|
*
|
||||||
* Returns selectivity (0..1), or -1 if we fail to estimate selectivity.
|
* Returns selectivity (0..1), or -1 if we fail to estimate selectivity.
|
||||||
*/
|
*/
|
||||||
@ -99,9 +101,8 @@ scalararraysel_containment(PlannerInfo *root,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Aggressively reduce leftop to a constant, if possible.
|
* leftop must be a constant, else punt.
|
||||||
*/
|
*/
|
||||||
leftop = estimate_expression_value(root, leftop);
|
|
||||||
if (!IsA(leftop, Const))
|
if (!IsA(leftop, Const))
|
||||||
{
|
{
|
||||||
ReleaseVariableStats(vardata);
|
ReleaseVariableStats(vardata);
|
||||||
|
@ -1734,6 +1734,10 @@ scalararraysel(PlannerInfo *root,
|
|||||||
leftop = (Node *) linitial(clause->args);
|
leftop = (Node *) linitial(clause->args);
|
||||||
rightop = (Node *) lsecond(clause->args);
|
rightop = (Node *) lsecond(clause->args);
|
||||||
|
|
||||||
|
/* aggressively reduce both sides to constants */
|
||||||
|
leftop = estimate_expression_value(root, leftop);
|
||||||
|
rightop = estimate_expression_value(root, rightop);
|
||||||
|
|
||||||
/* get nominal (after relabeling) element type of rightop */
|
/* get nominal (after relabeling) element type of rightop */
|
||||||
nominal_element_type = get_base_element_type(exprType(rightop));
|
nominal_element_type = get_base_element_type(exprType(rightop));
|
||||||
if (!OidIsValid(nominal_element_type))
|
if (!OidIsValid(nominal_element_type))
|
||||||
@ -6855,7 +6859,8 @@ gincost_pattern(IndexOptInfo *index, int indexcol,
|
|||||||
* appropriately. If the query is unsatisfiable, return false.
|
* appropriately. If the query is unsatisfiable, return false.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
gincost_opexpr(IndexOptInfo *index, OpExpr *clause, GinQualCounts *counts)
|
gincost_opexpr(PlannerInfo *root, IndexOptInfo *index, OpExpr *clause,
|
||||||
|
GinQualCounts *counts)
|
||||||
{
|
{
|
||||||
Node *leftop = get_leftop((Expr *) clause);
|
Node *leftop = get_leftop((Expr *) clause);
|
||||||
Node *rightop = get_rightop((Expr *) clause);
|
Node *rightop = get_rightop((Expr *) clause);
|
||||||
@ -6879,6 +6884,9 @@ gincost_opexpr(IndexOptInfo *index, OpExpr *clause, GinQualCounts *counts)
|
|||||||
operand = NULL; /* keep compiler quiet */
|
operand = NULL; /* keep compiler quiet */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* aggressively reduce to a constant, and look through relabeling */
|
||||||
|
operand = estimate_expression_value(root, operand);
|
||||||
|
|
||||||
if (IsA(operand, RelabelType))
|
if (IsA(operand, RelabelType))
|
||||||
operand = (Node *) ((RelabelType *) operand)->arg;
|
operand = (Node *) ((RelabelType *) operand)->arg;
|
||||||
|
|
||||||
@ -6917,7 +6925,8 @@ gincost_opexpr(IndexOptInfo *index, OpExpr *clause, GinQualCounts *counts)
|
|||||||
* by N, causing gincostestimate to scale up its estimates accordingly.
|
* by N, causing gincostestimate to scale up its estimates accordingly.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
gincost_scalararrayopexpr(IndexOptInfo *index, ScalarArrayOpExpr *clause,
|
gincost_scalararrayopexpr(PlannerInfo *root,
|
||||||
|
IndexOptInfo *index, ScalarArrayOpExpr *clause,
|
||||||
double numIndexEntries,
|
double numIndexEntries,
|
||||||
GinQualCounts *counts)
|
GinQualCounts *counts)
|
||||||
{
|
{
|
||||||
@ -6942,6 +6951,9 @@ gincost_scalararrayopexpr(IndexOptInfo *index, ScalarArrayOpExpr *clause,
|
|||||||
if ((indexcol = find_index_column(leftop, index)) < 0)
|
if ((indexcol = find_index_column(leftop, index)) < 0)
|
||||||
elog(ERROR, "could not match index to operand");
|
elog(ERROR, "could not match index to operand");
|
||||||
|
|
||||||
|
/* aggressively reduce to a constant, and look through relabeling */
|
||||||
|
rightop = estimate_expression_value(root, rightop);
|
||||||
|
|
||||||
if (IsA(rightop, RelabelType))
|
if (IsA(rightop, RelabelType))
|
||||||
rightop = (Node *) ((RelabelType *) rightop)->arg;
|
rightop = (Node *) ((RelabelType *) rightop)->arg;
|
||||||
|
|
||||||
@ -7159,7 +7171,8 @@ gincostestimate(PG_FUNCTION_ARGS)
|
|||||||
clause = rinfo->clause;
|
clause = rinfo->clause;
|
||||||
if (IsA(clause, OpExpr))
|
if (IsA(clause, OpExpr))
|
||||||
{
|
{
|
||||||
matchPossible = gincost_opexpr(index,
|
matchPossible = gincost_opexpr(root,
|
||||||
|
index,
|
||||||
(OpExpr *) clause,
|
(OpExpr *) clause,
|
||||||
&counts);
|
&counts);
|
||||||
if (!matchPossible)
|
if (!matchPossible)
|
||||||
@ -7167,7 +7180,8 @@ gincostestimate(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
else if (IsA(clause, ScalarArrayOpExpr))
|
else if (IsA(clause, ScalarArrayOpExpr))
|
||||||
{
|
{
|
||||||
matchPossible = gincost_scalararrayopexpr(index,
|
matchPossible = gincost_scalararrayopexpr(root,
|
||||||
|
index,
|
||||||
(ScalarArrayOpExpr *) clause,
|
(ScalarArrayOpExpr *) clause,
|
||||||
numEntries,
|
numEntries,
|
||||||
&counts);
|
&counts);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user