Enable using IS NOT DISTINCT FROM in hash and merge joins

From: Chi Gao <chi(dot)gao(at)microfun(dot)com>
To: "pgsql-hackers(at)lists(dot)postgresql(dot)org" <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Enable using IS NOT DISTINCT FROM in hash and merge joins
Date: 2018-09-04 09:14:35
Message-ID: HK0PR02MB2707EC901676E6749749197897030@HK0PR02MB2707.apcprd02.prod.outlook.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello,

We are using PostgreSQL to execute some SQL scripts "auto translated" from HIVE QL, where the join operator "<=>" is heavily used. The semantic same operator in PostgreSQL is "IS NOT DISTINCT FROM".

However, we found when "IS NOT DISTINCT FROM" is used in joins, only nested loop plan can be generated, which is confirmed here https://www.postgresql.org/message-id/13950.1511879733%40sss.pgh.pa.us and here https://postgrespro.com/list/thread-id/2059856 .

In another discussion someone suggests using coalesce(...) to replace NULLs to some special value, but in similar situation as in that thread, we have no reliable way to conclude a special value for any expression.

So I hacked the PG10 code to support using "IS NOT DISTINCT FROM" in hash and merge joins (not touching the indexes). It works in our environment, but I want to know if my approach is making sense, or is going to make damage.

There are 6 kinds of changes, and to be honest, none of them I am confident is doing in correct way...so please advise:
- I do this by first reversing the meaning of DistinctExpr, from "IS DISTINCT FROM" to "IS NOT DISTINCT FROM", which will be simpler to process in joins, because "IS NOT DISTINCT FROM" is closer to "=". (backend/parser/parse_expr.c, backend/utils/adt/ruleutils.c)
- The execution logic of DistinctExpr internally already reverts the result, because above change cancels it out, I revert it back. (backend/executor/execExprInterp.c, backend/optimizer/path/clausesel.c)
- In hash joins, I need to tell the executor that "NULL matches NULL" when the operator is "IS NOT DISTINCT FROM". I cannot figure out the best way for passing such information down, so I just ORed 0x8000000 to the operator Oid List. As no code in other parts is doing so, please advise a better approach, should I add a Bitmapset to pass the flags? Or should I define a new Node type to include both Oid and a bool flag? (backend/executor/nodeHashjoin.c, backend/executor/nodeHash.c)
- To support merge join, I added a nulleqnull bool flag in SortSupportData to bypass the "stop merging earlier when NULLs is reached" logic when the join operator is DistinctExpr. I think there is a padding gap after "bool abbreviate;", so I add the new flag after that, just want to keep binary compatibility in case something depends on it... (backend/executor/nodeMergejoin.c, include/utils/sortsupport.h)
- In create_join_clause, reconsider_outer_join_clause, and reconsider_full_join_clause functions, the derived expression generated by call to build_implied_join_equality outputs OpExpr for DistictExpr, because they are same in definition, I just patch the resulting node back to DistinctExpr if input is DistinctExpr. (backend/optimizer/path/equivclass.c)
- All other changes are for necessary code paths only allow OpExpr, I added logic to allow DistinctExpr too.

The patch in attachment is based on commit 821200405cc3f25fda28c5f58d17d640e25559b8.

Thanks!

Gao, Chi
Beijing Microfun Co. Ltd.

Attachment Content-Type Size
enable_is_not_distinct_from_in_hash_and_merge_joins.patch application/octet-stream 16.4 KB

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Kyotaro HORIGUCHI 2018-09-04 09:16:10 Re: A strange GiST error message or fillfactor of GiST build
Previous Message Amit Langote 2018-09-04 08:53:11 Re: executor relation handling