@@ -1748,16 +1748,34 @@ explain (analyze, costs off, summary off, timing off) execute ab_q3 (2, 2);
1748
1748
(10 rows)
1749
1749
1750
1750
-- Parallel append
1751
+ -- Suppress the number of loops each parallel node runs for. This is because
1752
+ -- more than one worker may run the same parallel node if timing conditions
1753
+ -- are just right, which destabilizes the test.
1754
+ create function explain_parallel_append(text, int[]) returns setof text
1755
+ language plpgsql as
1756
+ $$
1757
+ declare
1758
+ ln text;
1759
+ args text := string_agg(u::text, ', ') from unnest($2) u;
1760
+ begin
1761
+ for ln in
1762
+ execute format('explain (analyze, costs off, summary off, timing off) execute %s(%s)',
1763
+ $1, args)
1764
+ loop
1765
+ if ln like '%Parallel%' then
1766
+ ln := regexp_replace(ln, 'loops=\d*', 'loops=N');
1767
+ end if;
1768
+ return next ln;
1769
+ end loop;
1770
+ end;
1771
+ $$;
1751
1772
prepare ab_q4 (int, int) as
1752
1773
select avg(a) from ab where a between $1 and $2 and b < 4;
1753
1774
-- Encourage use of parallel plans
1754
1775
set parallel_setup_cost = 0;
1755
1776
set parallel_tuple_cost = 0;
1756
1777
set min_parallel_table_scan_size = 0;
1757
- -- set this so we get a parallel plan
1758
1778
set max_parallel_workers_per_gather = 2;
1759
- -- and zero this so that workers don't destabilize the explain output
1760
- set max_parallel_workers = 0;
1761
1779
-- Execute query 5 times to allow choose_custom_plan
1762
1780
-- to start considering a generic plan.
1763
1781
execute ab_q4 (1, 8);
@@ -1790,21 +1808,21 @@ execute ab_q4 (1, 8);
1790
1808
1791
1809
(1 row)
1792
1810
1793
- explain (analyze, costs off, summary off, timing off) execute ab_q4 ( 2, 2);
1794
- QUERY PLAN
1811
+ select explain_parallel_append('ab_q4', '{ 2, 2}' );
1812
+ explain_parallel_append
1795
1813
-------------------------------------------------------------------------------
1796
1814
Finalize Aggregate (actual rows=1 loops=1)
1797
- -> Gather (actual rows=1 loops=1)
1815
+ -> Gather (actual rows=3 loops=1)
1798
1816
Workers Planned: 2
1799
- Workers Launched: 0
1800
- -> Partial Aggregate (actual rows=1 loops=1 )
1801
- -> Parallel Append (actual rows=0 loops=1 )
1817
+ Workers Launched: 2
1818
+ -> Partial Aggregate (actual rows=1 loops=3 )
1819
+ -> Parallel Append (actual rows=0 loops=N )
1802
1820
Subplans Removed: 6
1803
- -> Parallel Seq Scan on ab_a2_b1 (actual rows=0 loops=1 )
1821
+ -> Parallel Seq Scan on ab_a2_b1 (actual rows=0 loops=N )
1804
1822
Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
1805
- -> Parallel Seq Scan on ab_a2_b2 (actual rows=0 loops=1 )
1823
+ -> Parallel Seq Scan on ab_a2_b2 (actual rows=0 loops=N )
1806
1824
Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
1807
- -> Parallel Seq Scan on ab_a2_b3 (actual rows=0 loops=1 )
1825
+ -> Parallel Seq Scan on ab_a2_b3 (actual rows=0 loops=N )
1808
1826
Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
1809
1827
(13 rows)
1810
1828
@@ -1843,59 +1861,59 @@ execute ab_q5 (1, 2, 3);
1843
1861
1844
1862
(1 row)
1845
1863
1846
- explain (analyze, costs off, summary off, timing off) execute ab_q5 ( 1, 1, 1);
1847
- QUERY PLAN
1864
+ select explain_parallel_append('ab_q5', '{ 1, 1, 1}' );
1865
+ explain_parallel_append
1848
1866
-------------------------------------------------------------------------------
1849
1867
Finalize Aggregate (actual rows=1 loops=1)
1850
- -> Gather (actual rows=1 loops=1)
1868
+ -> Gather (actual rows=3 loops=1)
1851
1869
Workers Planned: 2
1852
- Workers Launched: 0
1853
- -> Partial Aggregate (actual rows=1 loops=1 )
1854
- -> Parallel Append (actual rows=0 loops=1 )
1870
+ Workers Launched: 2
1871
+ -> Partial Aggregate (actual rows=1 loops=3 )
1872
+ -> Parallel Append (actual rows=0 loops=N )
1855
1873
Subplans Removed: 6
1856
- -> Parallel Seq Scan on ab_a1_b1 (actual rows=0 loops=1 )
1874
+ -> Parallel Seq Scan on ab_a1_b1 (actual rows=0 loops=N )
1857
1875
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
1858
- -> Parallel Seq Scan on ab_a1_b2 (actual rows=0 loops=1 )
1876
+ -> Parallel Seq Scan on ab_a1_b2 (actual rows=0 loops=N )
1859
1877
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
1860
- -> Parallel Seq Scan on ab_a1_b3 (actual rows=0 loops=1 )
1878
+ -> Parallel Seq Scan on ab_a1_b3 (actual rows=0 loops=N )
1861
1879
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
1862
1880
(13 rows)
1863
1881
1864
- explain (analyze, costs off, summary off, timing off) execute ab_q5 ( 2, 3, 3);
1865
- QUERY PLAN
1882
+ select explain_parallel_append('ab_q5', '{ 2, 3, 3}' );
1883
+ explain_parallel_append
1866
1884
-------------------------------------------------------------------------------
1867
1885
Finalize Aggregate (actual rows=1 loops=1)
1868
- -> Gather (actual rows=1 loops=1)
1886
+ -> Gather (actual rows=3 loops=1)
1869
1887
Workers Planned: 2
1870
- Workers Launched: 0
1871
- -> Partial Aggregate (actual rows=1 loops=1 )
1872
- -> Parallel Append (actual rows=0 loops=1 )
1888
+ Workers Launched: 2
1889
+ -> Partial Aggregate (actual rows=1 loops=3 )
1890
+ -> Parallel Append (actual rows=0 loops=N )
1873
1891
Subplans Removed: 3
1874
- -> Parallel Seq Scan on ab_a2_b1 (actual rows=0 loops=1 )
1892
+ -> Parallel Seq Scan on ab_a2_b1 (actual rows=0 loops=N )
1875
1893
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
1876
- -> Parallel Seq Scan on ab_a2_b2 (actual rows=0 loops=1 )
1894
+ -> Parallel Seq Scan on ab_a2_b2 (actual rows=0 loops=N )
1877
1895
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
1878
- -> Parallel Seq Scan on ab_a2_b3 (actual rows=0 loops=1 )
1896
+ -> Parallel Seq Scan on ab_a2_b3 (actual rows=0 loops=N )
1879
1897
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
1880
- -> Parallel Seq Scan on ab_a3_b1 (actual rows=0 loops=1 )
1898
+ -> Parallel Seq Scan on ab_a3_b1 (actual rows=0 loops=N )
1881
1899
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
1882
- -> Parallel Seq Scan on ab_a3_b2 (actual rows=0 loops=1 )
1900
+ -> Parallel Seq Scan on ab_a3_b2 (actual rows=0 loops=N )
1883
1901
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
1884
- -> Parallel Seq Scan on ab_a3_b3 (actual rows=0 loops=1 )
1902
+ -> Parallel Seq Scan on ab_a3_b3 (actual rows=0 loops=N )
1885
1903
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
1886
1904
(19 rows)
1887
1905
1888
1906
-- Try some params whose values do not belong to any partition.
1889
1907
-- We'll still get a single subplan in this case, but it should not be scanned.
1890
- explain (analyze, costs off, summary off, timing off) execute ab_q5 ( 33, 44, 55);
1891
- QUERY PLAN
1908
+ select explain_parallel_append('ab_q5', '{ 33, 44, 55}' );
1909
+ explain_parallel_append
1892
1910
-------------------------------------------------------------------------------
1893
1911
Finalize Aggregate (actual rows=1 loops=1)
1894
- -> Gather (actual rows=1 loops=1)
1912
+ -> Gather (actual rows=3 loops=1)
1895
1913
Workers Planned: 2
1896
- Workers Launched: 0
1897
- -> Partial Aggregate (actual rows=1 loops=1 )
1898
- -> Parallel Append (actual rows=0 loops=1 )
1914
+ Workers Launched: 2
1915
+ -> Partial Aggregate (actual rows=1 loops=3 )
1916
+ -> Parallel Append (actual rows=0 loops=N )
1899
1917
Subplans Removed: 8
1900
1918
-> Parallel Seq Scan on ab_a1_b1 (never executed)
1901
1919
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
@@ -1951,16 +1969,16 @@ execute ab_q6 (1, 2, 3);
1951
1969
1952
1970
(1 row)
1953
1971
1954
- explain (analyze, costs off, summary off, timing off) execute ab_q6 ( 0, 0, 1);
1955
- QUERY PLAN
1972
+ select explain_parallel_append('ab_q6', '{ 0, 0, 1}' );
1973
+ explain_parallel_append
1956
1974
---------------------------------------------------------------------------------------------------
1957
1975
Finalize Aggregate (actual rows=1 loops=1)
1958
- -> Gather (actual rows=1 loops=1)
1976
+ -> Gather (actual rows=2 loops=1)
1959
1977
Workers Planned: 1
1960
- Workers Launched: 0
1961
- -> Partial Aggregate (actual rows=1 loops=1 )
1962
- -> Nested Loop (actual rows=0 loops=1 )
1963
- -> Parallel Seq Scan on lprt_a a (actual rows=102 loops=1 )
1978
+ Workers Launched: 1
1979
+ -> Partial Aggregate (actual rows=1 loops=2 )
1980
+ -> Nested Loop (actual rows=0 loops=2 )
1981
+ -> Parallel Seq Scan on lprt_a a (actual rows=51 loops=N )
1964
1982
Filter: (a = ANY ('{0,0,1}'::integer[]))
1965
1983
-> Append (actual rows=0 loops=102)
1966
1984
-> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=0 loops=2)
@@ -1988,12 +2006,12 @@ explain (analyze, costs off, summary off, timing off) execute ab_q6 (1, 0, 3);
1988
2006
QUERY PLAN
1989
2007
---------------------------------------------------------------------------------------------------
1990
2008
Finalize Aggregate (actual rows=1 loops=1)
1991
- -> Gather (actual rows=1 loops=1)
2009
+ -> Gather (actual rows=2 loops=1)
1992
2010
Workers Planned: 1
1993
- Workers Launched: 0
1994
- -> Partial Aggregate (actual rows=1 loops=1 )
1995
- -> Nested Loop (actual rows=0 loops=1 )
1996
- -> Parallel Seq Scan on lprt_a a (actual rows=104 loops=1 )
2011
+ Workers Launched: 1
2012
+ -> Partial Aggregate (actual rows=1 loops=2 )
2013
+ -> Nested Loop (actual rows=0 loops=2 )
2014
+ -> Parallel Seq Scan on lprt_a a (actual rows=52 loops=2 )
1997
2015
Filter: (a = ANY ('{1,0,3}'::integer[]))
1998
2016
-> Append (actual rows=0 loops=104)
1999
2017
-> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=0 loops=2)
@@ -2020,14 +2038,14 @@ explain (analyze, costs off, summary off, timing off) execute ab_q6 (1, 0, 0);
2020
2038
QUERY PLAN
2021
2039
---------------------------------------------------------------------------------------------------
2022
2040
Finalize Aggregate (actual rows=1 loops=1)
2023
- -> Gather (actual rows=1 loops=1)
2041
+ -> Gather (actual rows=2 loops=1)
2024
2042
Workers Planned: 1
2025
- Workers Launched: 0
2026
- -> Partial Aggregate (actual rows=1 loops=1 )
2027
- -> Nested Loop (actual rows=0 loops=1 )
2028
- -> Parallel Seq Scan on lprt_a a (actual rows=102 loops=1 )
2043
+ Workers Launched: 1
2044
+ -> Partial Aggregate (actual rows=1 loops=2 )
2045
+ -> Nested Loop (actual rows=0 loops=2 )
2046
+ -> Parallel Seq Scan on lprt_a a (actual rows=51 loops=2 )
2029
2047
Filter: (a = ANY ('{1,0,0}'::integer[]))
2030
- Rows Removed by Filter: 2
2048
+ Rows Removed by Filter: 1
2031
2049
-> Append (actual rows=0 loops=102)
2032
2050
-> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=0 loops=2)
2033
2051
Index Cond: (a = a.a)
@@ -2054,14 +2072,14 @@ explain (analyze, costs off, summary off, timing off) execute ab_q6 (1, 0, 0);
2054
2072
QUERY PLAN
2055
2073
--------------------------------------------------------------------------------------------
2056
2074
Finalize Aggregate (actual rows=1 loops=1)
2057
- -> Gather (actual rows=1 loops=1)
2075
+ -> Gather (actual rows=2 loops=1)
2058
2076
Workers Planned: 1
2059
- Workers Launched: 0
2060
- -> Partial Aggregate (actual rows=1 loops=1 )
2061
- -> Nested Loop (actual rows=0 loops=1 )
2062
- -> Parallel Seq Scan on lprt_a a (actual rows=100 loops=1 )
2077
+ Workers Launched: 1
2078
+ -> Partial Aggregate (actual rows=1 loops=2 )
2079
+ -> Nested Loop (actual rows=0 loops=2 )
2080
+ -> Parallel Seq Scan on lprt_a a (actual rows=50 loops=2 )
2063
2081
Filter: (a = ANY ('{1,0,0}'::integer[]))
2064
- Rows Removed by Filter: 2
2082
+ Rows Removed by Filter: 1
2065
2083
-> Append (actual rows=0 loops=100)
2066
2084
-> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (never executed)
2067
2085
Index Cond: (a = a.a)
0 commit comments