Hi, all.

Some of my clients use JOIN's with three - four clauses. Quite frequently, I see complaints on unreasonable switch of JOIN algorithm to Merge Join instead of Hash Join. Quick research have shown one weak place - estimation of an average bucket size in final_cost_hashjoin (see q2.sql in attachment) with very conservative strategy. Unlike estimation of groups, here we use smallest ndistinct value across all buckets instead of multiplying them (or trying to make multivariate analysis). It works fine for the case of one clause. But if we have many clauses, and if each has high value of ndistinct, we will overestimate average size of a bucket and, as a result, prefer to use Merge Join. As the example in attachment shows, it leads to worse plan than possible, sometimes drastically worse. I assume, this is done with fear of functional dependencies between hash clause components. But as for me, here we should go the same way, as estimation of groups.
The attached patch shows a sketch of the solution.

--
regards,
Andrey Lepikhov
Postgres Professional

Attachment: q2.sql
Description: application/sql

diff --git a/src/backend/optimizer/path/costsize.c 
b/src/backend/optimizer/path/costsize.c
index ef475d95a1..26f26d6a40 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -4033,11 +4033,12 @@ final_cost_hashjoin(PlannerInfo *root, HashPath *path,
                                thismcvfreq = restrictinfo->left_mcvfreq;
                        }
 
-                       if (innerbucketsize > thisbucketsize)
-                               innerbucketsize = thisbucketsize;
-                       if (innermcvfreq > thismcvfreq)
-                               innermcvfreq = thismcvfreq;
+                       innerbucketsize *= thisbucketsize;
+                       innermcvfreq *= thismcvfreq;
                }
+
+               if (innerbucketsize > virtualbuckets)
+                       innerbucketsize = 1.0 / virtualbuckets;
        }
 
        /*

Reply via email to