mirror of
https://github.com/postgres/postgres.git
synced 2025-09-11 00:12:06 +03:00
Make estimation of mergejoin scan selectivities more robust, per recent
example from RaÇl GutiÅrrez.
This commit is contained in:
@@ -42,7 +42,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.90 2002/09/04 20:31:20 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.90.2.1 2003/01/22 20:17:06 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -645,8 +645,22 @@ cost_mergejoin(Path *path, Query *root,
|
|||||||
innerscansel = firstclause->left_mergescansel;
|
innerscansel = firstclause->left_mergescansel;
|
||||||
}
|
}
|
||||||
|
|
||||||
outer_rows = outer_path->parent->rows * outerscansel;
|
/* convert selectivity to row count; must scan at least one row */
|
||||||
inner_rows = inner_path->parent->rows * innerscansel;
|
|
||||||
|
outer_rows = ceil(outer_path->parent->rows * outerscansel);
|
||||||
|
if (outer_rows < 1)
|
||||||
|
outer_rows = 1;
|
||||||
|
inner_rows = ceil(inner_path->parent->rows * innerscansel);
|
||||||
|
if (inner_rows < 1)
|
||||||
|
inner_rows = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Readjust scan selectivities to account for above rounding. This is
|
||||||
|
* normally an insignificant effect, but when there are only a few rows
|
||||||
|
* in the inputs, failing to do this makes for a large percentage error.
|
||||||
|
*/
|
||||||
|
outerscansel = outer_rows / outer_path->parent->rows;
|
||||||
|
innerscansel = inner_rows / inner_path->parent->rows;
|
||||||
|
|
||||||
/* cost of source data */
|
/* cost of source data */
|
||||||
|
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.119 2002/10/19 02:56:16 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.119.2.1 2003/01/22 20:17:07 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -1740,7 +1740,9 @@ mergejoinscansel(Query *root, Node *clause,
|
|||||||
rsortop,
|
rsortop,
|
||||||
ltop,
|
ltop,
|
||||||
gtop,
|
gtop,
|
||||||
revltop;
|
leop,
|
||||||
|
revgtop,
|
||||||
|
revleop;
|
||||||
Datum leftmax,
|
Datum leftmax,
|
||||||
rightmax;
|
rightmax;
|
||||||
double selec;
|
double selec;
|
||||||
@@ -1779,35 +1781,49 @@ mergejoinscansel(Query *root, Node *clause,
|
|||||||
/* Look up the "left < right" and "left > right" operators */
|
/* Look up the "left < right" and "left > right" operators */
|
||||||
op_mergejoin_crossops(opno, <op, >op, NULL, NULL);
|
op_mergejoin_crossops(opno, <op, >op, NULL, NULL);
|
||||||
|
|
||||||
/* Look up the "right < left" operator */
|
/* Look up the "left <= right" operator */
|
||||||
revltop = get_commutator(gtop);
|
leop = get_negator(gtop);
|
||||||
if (!OidIsValid(revltop))
|
if (!OidIsValid(leop))
|
||||||
return; /* shouldn't happen */
|
return; /* insufficient info in catalogs */
|
||||||
|
|
||||||
|
/* Look up the "right > left" operator */
|
||||||
|
revgtop = get_commutator(ltop);
|
||||||
|
if (!OidIsValid(revgtop))
|
||||||
|
return; /* insufficient info in catalogs */
|
||||||
|
|
||||||
|
/* Look up the "right <= left" operator */
|
||||||
|
revleop = get_negator(revgtop);
|
||||||
|
if (!OidIsValid(revleop))
|
||||||
|
return; /* insufficient info in catalogs */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now, the fraction of the left variable that will be scanned is the
|
* Now, the fraction of the left variable that will be scanned is the
|
||||||
* fraction that's <= the right-side maximum value. But only believe
|
* fraction that's <= the right-side maximum value. But only believe
|
||||||
* non-default estimates, else stick with our 1.0.
|
* non-default estimates, else stick with our 1.0.
|
||||||
*/
|
*/
|
||||||
selec = scalarineqsel(root, ltop, false, left,
|
selec = scalarineqsel(root, leop, false, left,
|
||||||
rightmax, right->vartype);
|
rightmax, right->vartype);
|
||||||
if (selec != DEFAULT_INEQ_SEL)
|
if (selec != DEFAULT_INEQ_SEL)
|
||||||
*leftscan = selec;
|
*leftscan = selec;
|
||||||
|
|
||||||
/* And similarly for the right variable. */
|
/* And similarly for the right variable. */
|
||||||
selec = scalarineqsel(root, revltop, false, right,
|
selec = scalarineqsel(root, revleop, false, right,
|
||||||
leftmax, left->vartype);
|
leftmax, left->vartype);
|
||||||
if (selec != DEFAULT_INEQ_SEL)
|
if (selec != DEFAULT_INEQ_SEL)
|
||||||
*rightscan = selec;
|
*rightscan = selec;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only one of the two fractions can really be less than 1.0; believe
|
* Only one of the two fractions can really be less than 1.0; believe
|
||||||
* the smaller estimate and reset the other one to exactly 1.0.
|
* the smaller estimate and reset the other one to exactly 1.0. If we
|
||||||
|
* get exactly equal estimates (as can easily happen with self-joins),
|
||||||
|
* believe neither.
|
||||||
*/
|
*/
|
||||||
if (*leftscan > *rightscan)
|
if (*leftscan > *rightscan)
|
||||||
*leftscan = 1.0;
|
*leftscan = 1.0;
|
||||||
else
|
else if (*leftscan < *rightscan)
|
||||||
*rightscan = 1.0;
|
*rightscan = 1.0;
|
||||||
|
else
|
||||||
|
*leftscan = *rightscan = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user