Re: Parallel append plan instability/randomness

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: Parallel append plan instability/randomness
Дата
Msg-id 4944.1515446989@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: Parallel append plan instability/randomness  (Tom Lane <tgl@sss.pgh.pa.us>)
Список pgsql-hackers
I wrote:
>> In the regression test case at hand, the startup costs are all zero so
>> this change wouldn't improve the test case's stability.  So I'm thinking
>> that in addition, it would be a good idea for these functions to break
>> exact compare_path_costs ties in some arbitrary but deterministic way,
>> rather than letting qsort() have the final say on what happens.  If the
>> subplans were all simple relation scans we could order them by planner
>> relid, but I'm not sure what to do if they're not.

> Ah, I have an idea --- let's create a bms_compare() qsort comparator for
> bitmapsets, and use that on the paths' relid sets.  It hardly matters
> what the exact semantics of the comparator are, as long as it behaves
> sanely for equal sets.

Concretely, I propose the attached.  I spent a little bit of extra effort
on the comparator in hopes that it might be useful for something else.

            regards, tom lane

diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c
index 733fe3c..edcd19a 100644
*** a/src/backend/nodes/bitmapset.c
--- b/src/backend/nodes/bitmapset.c
*************** bms_equal(const Bitmapset *a, const Bitm
*** 173,178 ****
--- 173,222 ----
  }

  /*
+  * bms_compare - qsort-style comparator for bitmapsets
+  *
+  * This guarantees to report values as equal iff bms_equal would say they are
+  * equal.  Otherwise, the highest-numbered bit that is set in one value but
+  * not the other determines the result.  (This rule means that, for example,
+  * {6} is greater than {5}, which seems plausible.)
+  */
+ int
+ bms_compare(const Bitmapset *a, const Bitmapset *b)
+ {
+     int            shortlen;
+     int            i;
+
+     /* Handle cases where either input is NULL */
+     if (a == NULL)
+         return bms_is_empty(b) ? 0 : -1;
+     else if (b == NULL)
+         return bms_is_empty(a) ? 0 : +1;
+     /* Handle cases where one input is longer than the other */
+     shortlen = Min(a->nwords, b->nwords);
+     for (i = shortlen; i < a->nwords; i++)
+     {
+         if (a->words[i] != 0)
+             return +1;
+     }
+     for (i = shortlen; i < b->nwords; i++)
+     {
+         if (b->words[i] != 0)
+             return -1;
+     }
+     /* Process words in common */
+     i = shortlen;
+     while (--i >= 0)
+     {
+         bitmapword    aw = a->words[i];
+         bitmapword    bw = b->words[i];
+
+         if (aw != bw)
+             return (aw > bw) ? +1 : -1;
+     }
+     return 0;
+ }
+
+ /*
   * bms_make_singleton - build a bitmapset containing a single member
   */
  Bitmapset *
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 7df8761..5c2b996 100644
*** a/src/backend/optimizer/util/pathnode.c
--- b/src/backend/optimizer/util/pathnode.c
*************** create_append_path(RelOptInfo *rel,
*** 1274,1311 ****

  /*
   * append_total_cost_compare
!  *      list_qsort comparator for sorting append child paths by total_cost
   */
  static int
  append_total_cost_compare(const void *a, const void *b)
  {
      Path       *path1 = (Path *) lfirst(*(ListCell **) a);
      Path       *path2 = (Path *) lfirst(*(ListCell **) b);

!     if (path1->total_cost > path2->total_cost)
!         return -1;
!     if (path1->total_cost < path2->total_cost)
!         return 1;
!
!     return 0;
  }

  /*
   * append_startup_cost_compare
!  *      list_qsort comparator for sorting append child paths by startup_cost
   */
  static int
  append_startup_cost_compare(const void *a, const void *b)
  {
      Path       *path1 = (Path *) lfirst(*(ListCell **) a);
      Path       *path2 = (Path *) lfirst(*(ListCell **) b);

!     if (path1->startup_cost > path2->startup_cost)
!         return -1;
!     if (path1->startup_cost < path2->startup_cost)
!         return 1;
!
!     return 0;
  }

  /*
--- 1274,1317 ----

  /*
   * append_total_cost_compare
!  *      qsort comparator for sorting append child paths by total_cost descending
!  *
!  * For equal total costs, we fall back to comparing startup costs; if those
!  * are equal too, break ties using bms_compare on the paths' relids.
!  * (This is to avoid getting unpredictable results from qsort.)
   */
  static int
  append_total_cost_compare(const void *a, const void *b)
  {
      Path       *path1 = (Path *) lfirst(*(ListCell **) a);
      Path       *path2 = (Path *) lfirst(*(ListCell **) b);
+     int            cmp;

!     cmp = compare_path_costs(path1, path2, TOTAL_COST);
!     if (cmp == 0)
!         cmp = bms_compare(path1->parent->relids, path2->parent->relids);
!     return -cmp;
  }

  /*
   * append_startup_cost_compare
!  *      qsort comparator for sorting append child paths by startup_cost descending
!  *
!  * For equal startup costs, we fall back to comparing total costs; if those
!  * are equal too, break ties using bms_compare on the paths' relids.
!  * (This is to avoid getting unpredictable results from qsort.)
   */
  static int
  append_startup_cost_compare(const void *a, const void *b)
  {
      Path       *path1 = (Path *) lfirst(*(ListCell **) a);
      Path       *path2 = (Path *) lfirst(*(ListCell **) b);
+     int            cmp;

!     cmp = compare_path_costs(path1, path2, STARTUP_COST);
!     if (cmp == 0)
!         cmp = bms_compare(path1->parent->relids, path2->parent->relids);
!     return -cmp;
  }

  /*
diff --git a/src/include/nodes/bitmapset.h b/src/include/nodes/bitmapset.h
index 15397e9..67e8920 100644
*** a/src/include/nodes/bitmapset.h
--- b/src/include/nodes/bitmapset.h
*************** typedef enum
*** 65,70 ****
--- 65,71 ----

  extern Bitmapset *bms_copy(const Bitmapset *a);
  extern bool bms_equal(const Bitmapset *a, const Bitmapset *b);
+ extern int    bms_compare(const Bitmapset *a, const Bitmapset *b);
  extern Bitmapset *bms_make_singleton(int x);
  extern void bms_free(Bitmapset *a);

diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out
index 7824ca5..5f73be4 100644
*** a/src/test/regress/expected/select_parallel.out
--- b/src/test/regress/expected/select_parallel.out
*************** explain (costs off)
*** 21,32 ****
           Workers Planned: 3
           ->  Partial Aggregate
                 ->  Parallel Append
!                      ->  Parallel Seq Scan on a_star
!                      ->  Parallel Seq Scan on b_star
!                      ->  Parallel Seq Scan on c_star
                       ->  Parallel Seq Scan on d_star
                       ->  Parallel Seq Scan on e_star
!                      ->  Parallel Seq Scan on f_star
  (11 rows)

  select round(avg(aa)), sum(aa) from a_star a1;
--- 21,32 ----
           Workers Planned: 3
           ->  Partial Aggregate
                 ->  Parallel Append
!                      ->  Parallel Seq Scan on f_star
                       ->  Parallel Seq Scan on d_star
                       ->  Parallel Seq Scan on e_star
!                      ->  Parallel Seq Scan on c_star
!                      ->  Parallel Seq Scan on b_star
!                      ->  Parallel Seq Scan on a_star
  (11 rows)

  select round(avg(aa)), sum(aa) from a_star a1;
*************** explain (costs off)
*** 49,58 ****
                 ->  Parallel Append
                       ->  Seq Scan on d_star
                       ->  Seq Scan on c_star
-                      ->  Parallel Seq Scan on a_star
-                      ->  Parallel Seq Scan on b_star
-                      ->  Parallel Seq Scan on e_star
                       ->  Parallel Seq Scan on f_star
  (11 rows)

  select round(avg(aa)), sum(aa) from a_star a2;
--- 49,58 ----
                 ->  Parallel Append
                       ->  Seq Scan on d_star
                       ->  Seq Scan on c_star
                       ->  Parallel Seq Scan on f_star
+                      ->  Parallel Seq Scan on e_star
+                      ->  Parallel Seq Scan on b_star
+                      ->  Parallel Seq Scan on a_star
  (11 rows)

  select round(avg(aa)), sum(aa) from a_star a2;
*************** explain (costs off)
*** 75,85 ****
           Workers Planned: 3
           ->  Partial Aggregate
                 ->  Parallel Append
-                      ->  Seq Scan on d_star
                       ->  Seq Scan on f_star
                       ->  Seq Scan on e_star
-                      ->  Seq Scan on b_star
                       ->  Seq Scan on c_star
                       ->  Seq Scan on a_star
  (11 rows)

--- 75,85 ----
           Workers Planned: 3
           ->  Partial Aggregate
                 ->  Parallel Append
                       ->  Seq Scan on f_star
+                      ->  Seq Scan on d_star
                       ->  Seq Scan on e_star
                       ->  Seq Scan on c_star
+                      ->  Seq Scan on b_star
                       ->  Seq Scan on a_star
  (11 rows)


В списке pgsql-hackers по дате отправления:

Предыдущее
От: Alvaro Herrera
Дата:
Сообщение: Re: update portal-related memory context names and API
Следующее
От: Alexander Korotkov
Дата:
Сообщение: Re: Challenges preventing us moving to 64 bit transaction id (XID)?