mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Parallel Hash Full Join.
Full and right outer joins were not supported in the initial implementation of Parallel Hash Join because of deadlock hazards (see discussion). Therefore FULL JOIN inhibited parallelism, as the other join strategies can't do that in parallel either. Add a new PHJ phase PHJ_BATCH_SCAN that scans for unmatched tuples on the inner side of one batch's hash table. For now, sidestep the deadlock problem by terminating parallelism there. The last process to arrive at that phase emits the unmatched tuples, while others detach and are free to go and work on other batches, if there are any, but otherwise they finish the join early. That unfairness is considered acceptable for now, because it's better than no parallelism at all. The build and probe phases are run in parallel, and the new scan-for-unmatched phase, while serial, is usually applied to the smaller of the two relations and is either limited by some multiple of work_mem, or it's too big and is partitioned into batches and then the situation is improved by batch-level parallelism. Author: Melanie Plageman <melanieplageman@gmail.com> Author: Thomas Munro <thomas.munro@gmail.com> Reviewed-by: Thomas Munro <thomas.munro@gmail.com> Discussion: https://postgr.es/m/CA%2BhUKG%2BA6ftXPz4oe92%2Bx8Er%2BxpGZqto70-Q_ERwRaSyA%3DafNg%40mail.gmail.com
This commit is contained in:
@ -2193,15 +2193,9 @@ hash_inner_and_outer(PlannerInfo *root,
|
||||
* able to properly guarantee uniqueness. Similarly, we can't handle
|
||||
* JOIN_FULL and JOIN_RIGHT, because they can produce false null
|
||||
* extended rows. Also, the resulting path must not be parameterized.
|
||||
* We would be able to support JOIN_FULL and JOIN_RIGHT for Parallel
|
||||
* Hash, since in that case we're back to a single hash table with a
|
||||
* single set of match bits for each batch, but that will require
|
||||
* figuring out a deadlock-free way to wait for the probe to finish.
|
||||
*/
|
||||
if (joinrel->consider_parallel &&
|
||||
save_jointype != JOIN_UNIQUE_OUTER &&
|
||||
save_jointype != JOIN_FULL &&
|
||||
save_jointype != JOIN_RIGHT &&
|
||||
outerrel->partial_pathlist != NIL &&
|
||||
bms_is_empty(joinrel->lateral_relids))
|
||||
{
|
||||
@ -2235,9 +2229,13 @@ hash_inner_and_outer(PlannerInfo *root,
|
||||
* total inner path will also be parallel-safe, but if not, we'll
|
||||
* have to search for the cheapest safe, unparameterized inner
|
||||
* path. If doing JOIN_UNIQUE_INNER, we can't use any alternative
|
||||
* inner path.
|
||||
* inner path. If full or right join, we can't use parallelism
|
||||
* (building the hash table in each backend) because no one
|
||||
* process has all the match bits.
|
||||
*/
|
||||
if (cheapest_total_inner->parallel_safe)
|
||||
if (save_jointype == JOIN_FULL || save_jointype == JOIN_RIGHT)
|
||||
cheapest_safe_inner = NULL;
|
||||
else if (cheapest_total_inner->parallel_safe)
|
||||
cheapest_safe_inner = cheapest_total_inner;
|
||||
else if (save_jointype != JOIN_UNIQUE_INNER)
|
||||
cheapest_safe_inner =
|
||||
|
Reference in New Issue
Block a user