Skip to content

Commit 655d2d7

Browse files
committed
parameterized append paths
1 parent 713f55c commit 655d2d7

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed

pg_pathman.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
9999
List *all_child_pathkeys,
100100
PathKey *pathkeyAsc,
101101
PathKey *pathkeyDesc);
102+
static Path *get_cheapest_parameterized_child_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer);
102103

103104

104105
/*
@@ -1616,6 +1617,49 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
16161617
generate_mergeappend_paths(root, rel, live_childrels,
16171618
all_child_pathkeys, pathkeyAsc,
16181619
pathkeyDesc);
1620+
1621+
/*
1622+
* Build Append paths for each parameterization seen among the child rels.
1623+
* (This may look pretty expensive, but in most cases of practical
1624+
* interest, the child rels will expose mostly the same parameterizations,
1625+
* so that not that many cases actually get considered here.)
1626+
*
1627+
* The Append node itself cannot enforce quals, so all qual checking must
1628+
* be done in the child paths. This means that to have a parameterized
1629+
* Append path, we must have the exact same parameterization for each
1630+
* child path; otherwise some children might be failing to check the
1631+
* moved-down quals. To make them match up, we can try to increase the
1632+
* parameterization of lesser-parameterized paths.
1633+
*/
1634+
foreach(l, all_child_outers)
1635+
{
1636+
Relids required_outer = (Relids) lfirst(l);
1637+
ListCell *lcr;
1638+
1639+
/* Select the child paths for an Append with this parameterization */
1640+
subpaths = NIL;
1641+
subpaths_valid = true;
1642+
foreach(lcr, live_childrels)
1643+
{
1644+
RelOptInfo *childrel = (RelOptInfo *) lfirst(lcr);
1645+
Path *subpath;
1646+
1647+
subpath = get_cheapest_parameterized_child_path(root,
1648+
childrel,
1649+
required_outer);
1650+
if (subpath == NULL)
1651+
{
1652+
/* failed to make a suitable path for this child */
1653+
subpaths_valid = false;
1654+
break;
1655+
}
1656+
subpaths = accumulate_append_subpath(subpaths, subpath);
1657+
}
1658+
1659+
if (subpaths_valid)
1660+
add_path(rel, (Path *)
1661+
create_append_path(rel, subpaths, required_outer));
1662+
}
16191663
}
16201664

16211665
static List *
@@ -1624,7 +1668,78 @@ accumulate_append_subpath(List *subpaths, Path *path)
16241668
return lappend(subpaths, path);
16251669
}
16261670

1671+
/*
1672+
* get_cheapest_parameterized_child_path
1673+
* Get cheapest path for this relation that has exactly the requested
1674+
* parameterization.
1675+
*
1676+
* Returns NULL if unable to create such a path.
1677+
*/
1678+
static Path *
1679+
get_cheapest_parameterized_child_path(PlannerInfo *root, RelOptInfo *rel,
1680+
Relids required_outer)
1681+
{
1682+
Path *cheapest;
1683+
ListCell *lc;
1684+
1685+
/*
1686+
* Look up the cheapest existing path with no more than the needed
1687+
* parameterization. If it has exactly the needed parameterization, we're
1688+
* done.
1689+
*/
1690+
cheapest = get_cheapest_path_for_pathkeys(rel->pathlist,
1691+
NIL,
1692+
required_outer,
1693+
TOTAL_COST);
1694+
Assert(cheapest != NULL);
1695+
if (bms_equal(PATH_REQ_OUTER(cheapest), required_outer))
1696+
return cheapest;
16271697

1698+
/*
1699+
* Otherwise, we can "reparameterize" an existing path to match the given
1700+
* parameterization, which effectively means pushing down additional
1701+
* joinquals to be checked within the path's scan. However, some existing
1702+
* paths might check the available joinquals already while others don't;
1703+
* therefore, it's not clear which existing path will be cheapest after
1704+
* reparameterization. We have to go through them all and find out.
1705+
*/
1706+
cheapest = NULL;
1707+
foreach(lc, rel->pathlist)
1708+
{
1709+
Path *path = (Path *) lfirst(lc);
1710+
1711+
/* Can't use it if it needs more than requested parameterization */
1712+
if (!bms_is_subset(PATH_REQ_OUTER(path), required_outer))
1713+
continue;
1714+
1715+
/*
1716+
* Reparameterization can only increase the path's cost, so if it's
1717+
* already more expensive than the current cheapest, forget it.
1718+
*/
1719+
if (cheapest != NULL &&
1720+
compare_path_costs(cheapest, path, TOTAL_COST) <= 0)
1721+
continue;
1722+
1723+
/* Reparameterize if needed, then recheck cost */
1724+
if (!bms_equal(PATH_REQ_OUTER(path), required_outer))
1725+
{
1726+
path = reparameterize_path(root, path, required_outer, 1.0);
1727+
if (path == NULL)
1728+
continue; /* failed to reparameterize this one */
1729+
Assert(bms_equal(PATH_REQ_OUTER(path), required_outer));
1730+
1731+
if (cheapest != NULL &&
1732+
compare_path_costs(cheapest, path, TOTAL_COST) <= 0)
1733+
continue;
1734+
}
1735+
1736+
/* We have a new best path */
1737+
cheapest = path;
1738+
}
1739+
1740+
/* Return the best path, or NULL if we found no suitable candidate */
1741+
return cheapest;
1742+
}
16281743

16291744

16301745
//---------------------------------------------------------------

0 commit comments

Comments
 (0)