@@ -2013,9 +2013,14 @@ explain (analyze, costs off, summary off, timing off) select * from list_part wh
2013
2013
rollback;
2014
2014
drop table list_part;
2015
2015
-- Parallel append
2016
- -- Suppress the number of loops each parallel node runs for. This is because
2017
- -- more than one worker may run the same parallel node if timing conditions
2018
- -- are just right, which destabilizes the test.
2016
+ -- Parallel queries won't necessarily get as many workers as the planner
2017
+ -- asked for. This affects not only the "Workers Launched:" field of EXPLAIN
2018
+ -- results, but also row counts and loop counts for parallel scans, Gathers,
2019
+ -- and everything in between. This function filters out the values we can't
2020
+ -- rely on to be stable.
2021
+ -- This removes enough info that you might wonder why bother with EXPLAIN
2022
+ -- ANALYZE at all. The answer is that we need to see '(never executed)'
2023
+ -- notations because that's the only way to verify runtime pruning.
2019
2024
create function explain_parallel_append(text) returns setof text
2020
2025
language plpgsql as
2021
2026
$$
@@ -2026,9 +2031,8 @@ begin
2026
2031
execute format('explain (analyze, costs off, summary off, timing off) %s',
2027
2032
$1)
2028
2033
loop
2029
- if ln like '%Parallel%' then
2030
- ln := regexp_replace(ln, 'loops=\d*', 'loops=N');
2031
- end if;
2034
+ ln := regexp_replace(ln, 'Workers Launched: \d+', 'Workers Launched: N');
2035
+ ln := regexp_replace(ln, 'actual rows=\d+ loops=\d+', 'actual rows=N loops=N');
2032
2036
return next ln;
2033
2037
end loop;
2034
2038
end;
@@ -2075,18 +2079,18 @@ execute ab_q4 (1, 8);
2075
2079
select explain_parallel_append('execute ab_q4 (2, 2)');
2076
2080
explain_parallel_append
2077
2081
-------------------------------------------------------------------------------
2078
- Finalize Aggregate (actual rows=1 loops=1 )
2079
- -> Gather (actual rows=3 loops=1 )
2082
+ Finalize Aggregate (actual rows=N loops=N )
2083
+ -> Gather (actual rows=N loops=N )
2080
2084
Workers Planned: 2
2081
- Workers Launched:2
2082
- -> Partial Aggregate (actual rows=1 loops=3 )
2083
- -> Parallel Append (actual rows=0 loops=N)
2085
+ Workers Launched:N
2086
+ -> Partial Aggregate (actual rows=N loops=N )
2087
+ -> Parallel Append (actual rows=N loops=N)
2084
2088
Subplans Removed: 6
2085
- -> Parallel Seq Scan on ab_a2_b1 (actual rows=0 loops=N)
2089
+ -> Parallel Seq Scan on ab_a2_b1 (actual rows=N loops=N)
2086
2090
Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
2087
- -> Parallel Seq Scan on ab_a2_b2 (actual rows=0 loops=N)
2091
+ -> Parallel Seq Scan on ab_a2_b2 (actual rows=N loops=N)
2088
2092
Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
2089
- -> Parallel Seq Scan on ab_a2_b3 (actual rows=0 loops=N)
2093
+ -> Parallel Seq Scan on ab_a2_b3 (actual rows=N loops=N)
2090
2094
Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
2091
2095
(13 rows)
2092
2096
@@ -2128,42 +2132,42 @@ execute ab_q5 (1, 2, 3);
2128
2132
select explain_parallel_append('execute ab_q5 (1, 1, 1)');
2129
2133
explain_parallel_append
2130
2134
-------------------------------------------------------------------------------
2131
- Finalize Aggregate (actual rows=1 loops=1 )
2132
- -> Gather (actual rows=3 loops=1 )
2135
+ Finalize Aggregate (actual rows=N loops=N )
2136
+ -> Gather (actual rows=N loops=N )
2133
2137
Workers Planned: 2
2134
- Workers Launched:2
2135
- -> Partial Aggregate (actual rows=1 loops=3 )
2136
- -> Parallel Append (actual rows=0 loops=N)
2138
+ Workers Launched:N
2139
+ -> Partial Aggregate (actual rows=N loops=N )
2140
+ -> Parallel Append (actual rows=N loops=N)
2137
2141
Subplans Removed: 6
2138
- -> Parallel Seq Scan on ab_a1_b1 (actual rows=0 loops=N)
2142
+ -> Parallel Seq Scan on ab_a1_b1 (actual rows=N loops=N)
2139
2143
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
2140
- -> Parallel Seq Scan on ab_a1_b2 (actual rows=0 loops=N)
2144
+ -> Parallel Seq Scan on ab_a1_b2 (actual rows=N loops=N)
2141
2145
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
2142
- -> Parallel Seq Scan on ab_a1_b3 (actual rows=0 loops=N)
2146
+ -> Parallel Seq Scan on ab_a1_b3 (actual rows=N loops=N)
2143
2147
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
2144
2148
(13 rows)
2145
2149
2146
2150
select explain_parallel_append('execute ab_q5 (2, 3, 3)');
2147
2151
explain_parallel_append
2148
2152
-------------------------------------------------------------------------------
2149
- Finalize Aggregate (actual rows=1 loops=1 )
2150
- -> Gather (actual rows=3 loops=1 )
2153
+ Finalize Aggregate (actual rows=N loops=N )
2154
+ -> Gather (actual rows=N loops=N )
2151
2155
Workers Planned: 2
2152
- Workers Launched:2
2153
- -> Partial Aggregate (actual rows=1 loops=3 )
2154
- -> Parallel Append (actual rows=0 loops=N)
2156
+ Workers Launched:N
2157
+ -> Partial Aggregate (actual rows=N loops=N )
2158
+ -> Parallel Append (actual rows=N loops=N)
2155
2159
Subplans Removed: 3
2156
- -> Parallel Seq Scan on ab_a2_b1 (actual rows=0 loops=N)
2160
+ -> Parallel Seq Scan on ab_a2_b1 (actual rows=N loops=N)
2157
2161
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
2158
- -> Parallel Seq Scan on ab_a2_b2 (actual rows=0 loops=N)
2162
+ -> Parallel Seq Scan on ab_a2_b2 (actual rows=N loops=N)
2159
2163
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
2160
- -> Parallel Seq Scan on ab_a2_b3 (actual rows=0 loops=N)
2164
+ -> Parallel Seq Scan on ab_a2_b3 (actual rows=N loops=N)
2161
2165
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
2162
- -> Parallel Seq Scan on ab_a3_b1 (actual rows=0 loops=N)
2166
+ -> Parallel Seq Scan on ab_a3_b1 (actual rows=N loops=N)
2163
2167
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
2164
- -> Parallel Seq Scan on ab_a3_b2 (actual rows=0 loops=N)
2168
+ -> Parallel Seq Scan on ab_a3_b2 (actual rows=N loops=N)
2165
2169
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
2166
- -> Parallel Seq Scan on ab_a3_b3 (actual rows=0 loops=N)
2170
+ -> Parallel Seq Scan on ab_a3_b3 (actual rows=N loops=N)
2167
2171
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
2168
2172
(19 rows)
2169
2173
@@ -2172,12 +2176,12 @@ select explain_parallel_append('execute ab_q5 (2, 3, 3)');
2172
2176
select explain_parallel_append('execute ab_q5 (33, 44, 55)');
2173
2177
explain_parallel_append
2174
2178
-------------------------------------------------------------------------------
2175
- Finalize Aggregate (actual rows=1 loops=1 )
2176
- -> Gather (actual rows=3 loops=1 )
2179
+ Finalize Aggregate (actual rows=N loops=N )
2180
+ -> Gather (actual rows=N loops=N )
2177
2181
Workers Planned: 2
2178
- Workers Launched:2
2179
- -> Partial Aggregate (actual rows=1 loops=3 )
2180
- -> Parallel Append (actual rows=0 loops=N)
2182
+ Workers Launched:N
2183
+ -> Partial Aggregate (actual rows=N loops=N )
2184
+ -> Parallel Append (actual rows=N loops=N)
2181
2185
Subplans Removed: 8
2182
2186
-> Parallel Seq Scan on ab_a1_b1 (never executed)
2183
2187
Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
@@ -2187,21 +2191,21 @@ select explain_parallel_append('execute ab_q5 (33, 44, 55)');
2187
2191
select explain_parallel_append('select count(*) from ab where (a = (select 1) or a = (select 3)) and b = 2');
2188
2192
explain_parallel_append
2189
2193
-------------------------------------------------------------------------
2190
- Aggregate (actual rows=1 loops=1 )
2194
+ Aggregate (actual rows=N loops=N )
2191
2195
InitPlan 1 (returns $0)
2192
- -> Result (actual rows=1 loops=1 )
2196
+ -> Result (actual rows=N loops=N )
2193
2197
InitPlan 2 (returns $1)
2194
- -> Result (actual rows=1 loops=1 )
2195
- -> Gather (actual rows=0 loops=1 )
2198
+ -> Result (actual rows=N loops=N )
2199
+ -> Gather (actual rows=N loops=N )
2196
2200
Workers Planned: 2
2197
2201
Params Evaluated: $0, $1
2198
- Workers Launched:2
2199
- -> Parallel Append (actual rows=0 loops=N)
2200
- -> Parallel Seq Scan on ab_a1_b2 (actual rows=0 loops=N)
2202
+ Workers Launched:N
2203
+ -> Parallel Append (actual rows=N loops=N)
2204
+ -> Parallel Seq Scan on ab_a1_b2 (actual rows=N loops=N)
2201
2205
Filter: ((b = 2) AND ((a = $0) OR (a = $1)))
2202
2206
-> Parallel Seq Scan on ab_a2_b2 (never executed)
2203
2207
Filter: ((b = 2) AND ((a = $0) OR (a = $1)))
2204
- -> Parallel Seq Scan on ab_a3_b2 (actual rows=0 loops=N)
2208
+ -> Parallel Seq Scan on ab_a3_b2 (actual rows=N loops=N)
2205
2209
Filter: ((b = 2) AND ((a = $0) OR (a = $1)))
2206
2210
(16 rows)
2207
2211
@@ -2226,20 +2230,20 @@ set enable_mergejoin = 0;
2226
2230
select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on ab.a = a.a where a.a in(0, 0, 1)');
2227
2231
explain_parallel_append
2228
2232
---------------------------------------------------------------------------------------------------
2229
- Finalize Aggregate (actual rows=1 loops=1 )
2230
- -> Gather (actual rows=2 loops=1 )
2233
+ Finalize Aggregate (actual rows=N loops=N )
2234
+ -> Gather (actual rows=N loops=N )
2231
2235
Workers Planned: 1
2232
- Workers Launched:1
2233
- -> Partial Aggregate (actual rows=1 loops=2 )
2234
- -> Nested Loop (actual rows=0 loops=2 )
2235
- -> Parallel Seq Scan on lprt_a a (actual rows=51 loops=N)
2236
+ Workers Launched:N
2237
+ -> Partial Aggregate (actual rows=N loops=N )
2238
+ -> Nested Loop (actual rows=N loops=N )
2239
+ -> Parallel Seq Scan on lprt_a a (actual rows=N loops=N)
2236
2240
Filter: (a = ANY ('{0,0,1}'::integer[]))
2237
- -> Append (actual rows=0 loops=102 )
2238
- -> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=0 loops=2 )
2241
+ -> Append (actual rows=N loops=N )
2242
+ -> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=N loops=N )
2239
2243
Index Cond: (a = a.a)
2240
- -> Index Scan using ab_a1_b2_a_idx on ab_a1_b2 (actual rows=0 loops=2 )
2244
+ -> Index Scan using ab_a1_b2_a_idx on ab_a1_b2 (actual rows=N loops=N )
2241
2245
Index Cond: (a = a.a)
2242
- -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 (actual rows=0 loops=2 )
2246
+ -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 (actual rows=N loops=N )
2243
2247
Index Cond: (a = a.a)
2244
2248
-> Index Scan using ab_a2_b1_a_idx on ab_a2_b1 (never executed)
2245
2249
Index Cond: (a = a.a)
@@ -2260,20 +2264,20 @@ select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on
2260
2264
select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on ab.a = a.a + 0 where a.a in(0, 0, 1)');
2261
2265
explain_parallel_append
2262
2266
---------------------------------------------------------------------------------------------------
2263
- Finalize Aggregate (actual rows=1 loops=1 )
2264
- -> Gather (actual rows=2 loops=1 )
2267
+ Finalize Aggregate (actual rows=N loops=N )
2268
+ -> Gather (actual rows=N loops=N )
2265
2269
Workers Planned: 1
2266
- Workers Launched:1
2267
- -> Partial Aggregate (actual rows=1 loops=2 )
2268
- -> Nested Loop (actual rows=0 loops=2 )
2269
- -> Parallel Seq Scan on lprt_a a (actual rows=51 loops=N)
2270
+ Workers Launched:N
2271
+ -> Partial Aggregate (actual rows=N loops=N )
2272
+ -> Nested Loop (actual rows=N loops=N )
2273
+ -> Parallel Seq Scan on lprt_a a (actual rows=N loops=N)
2270
2274
Filter: (a = ANY ('{0,0,1}'::integer[]))
2271
- -> Append (actual rows=0 loops=102 )
2272
- -> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=0 loops=2 )
2275
+ -> Append (actual rows=N loops=N )
2276
+ -> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=N loops=N )
2273
2277
Index Cond: (a = (a.a + 0))
2274
- -> Index Scan using ab_a1_b2_a_idx on ab_a1_b2 (actual rows=0 loops=2 )
2278
+ -> Index Scan using ab_a1_b2_a_idx on ab_a1_b2 (actual rows=N loops=N )
2275
2279
Index Cond: (a = (a.a + 0))
2276
- -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 (actual rows=0 loops=2 )
2280
+ -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 (actual rows=N loops=N )
2277
2281
Index Cond: (a = (a.a + 0))
2278
2282
-> Index Scan using ab_a2_b1_a_idx on ab_a2_b1 (never executed)
2279
2283
Index Cond: (a = (a.a + 0))
@@ -2293,53 +2297,53 @@ insert into lprt_a values(3),(3);
2293
2297
select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on ab.a = a.a where a.a in(1, 0, 3)');
2294
2298
explain_parallel_append
2295
2299
---------------------------------------------------------------------------------------------------
2296
- Finalize Aggregate (actual rows=1 loops=1 )
2297
- -> Gather (actual rows=2 loops=1 )
2300
+ Finalize Aggregate (actual rows=N loops=N )
2301
+ -> Gather (actual rows=N loops=N )
2298
2302
Workers Planned: 1
2299
- Workers Launched:1
2300
- -> Partial Aggregate (actual rows=1 loops=2 )
2301
- -> Nested Loop (actual rows=0 loops=2 )
2302
- -> Parallel Seq Scan on lprt_a a (actual rows=52 loops=N)
2303
+ Workers Launched:N
2304
+ -> Partial Aggregate (actual rows=N loops=N )
2305
+ -> Nested Loop (actual rows=N loops=N )
2306
+ -> Parallel Seq Scan on lprt_a a (actual rows=N loops=N)
2303
2307
Filter: (a = ANY ('{1,0,3}'::integer[]))
2304
- -> Append (actual rows=0 loops=104 )
2305
- -> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=0 loops=2 )
2308
+ -> Append (actual rows=N loops=N )
2309
+ -> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=N loops=N )
2306
2310
Index Cond: (a = a.a)
2307
- -> Index Scan using ab_a1_b2_a_idx on ab_a1_b2 (actual rows=0 loops=2 )
2311
+ -> Index Scan using ab_a1_b2_a_idx on ab_a1_b2 (actual rows=N loops=N )
2308
2312
Index Cond: (a = a.a)
2309
- -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 (actual rows=0 loops=2 )
2313
+ -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 (actual rows=N loops=N )
2310
2314
Index Cond: (a = a.a)
2311
2315
-> Index Scan using ab_a2_b1_a_idx on ab_a2_b1 (never executed)
2312
2316
Index Cond: (a = a.a)
2313
2317
-> Index Scan using ab_a2_b2_a_idx on ab_a2_b2 (never executed)
2314
2318
Index Cond: (a = a.a)
2315
2319
-> Index Scan using ab_a2_b3_a_idx on ab_a2_b3 (never executed)
2316
2320
Index Cond: (a = a.a)
2317
- -> Index Scan using ab_a3_b1_a_idx on ab_a3_b1 (actual rows=0 loops=2 )
2321
+ -> Index Scan using ab_a3_b1_a_idx on ab_a3_b1 (actual rows=N loops=N )
2318
2322
Index Cond: (a = a.a)
2319
- -> Index Scan using ab_a3_b2_a_idx on ab_a3_b2 (actual rows=0 loops=2 )
2323
+ -> Index Scan using ab_a3_b2_a_idx on ab_a3_b2 (actual rows=N loops=N )
2320
2324
Index Cond: (a = a.a)
2321
- -> Index Scan using ab_a3_b3_a_idx on ab_a3_b3 (actual rows=0 loops=2 )
2325
+ -> Index Scan using ab_a3_b3_a_idx on ab_a3_b3 (actual rows=N loops=N )
2322
2326
Index Cond: (a = a.a)
2323
2327
(27 rows)
2324
2328
2325
2329
select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on ab.a = a.a where a.a in(1, 0, 0)');
2326
2330
explain_parallel_append
2327
2331
---------------------------------------------------------------------------------------------------
2328
- Finalize Aggregate (actual rows=1 loops=1 )
2329
- -> Gather (actual rows=2 loops=1 )
2332
+ Finalize Aggregate (actual rows=N loops=N )
2333
+ -> Gather (actual rows=N loops=N )
2330
2334
Workers Planned: 1
2331
- Workers Launched:1
2332
- -> Partial Aggregate (actual rows=1 loops=2 )
2333
- -> Nested Loop (actual rows=0 loops=2 )
2334
- -> Parallel Seq Scan on lprt_a a (actual rows=51 loops=N)
2335
+ Workers Launched:N
2336
+ -> Partial Aggregate (actual rows=N loops=N )
2337
+ -> Nested Loop (actual rows=N loops=N )
2338
+ -> Parallel Seq Scan on lprt_a a (actual rows=N loops=N)
2335
2339
Filter: (a = ANY ('{1,0,0}'::integer[]))
2336
2340
Rows Removed by Filter: 1
2337
- -> Append (actual rows=0 loops=102 )
2338
- -> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=0 loops=2 )
2341
+ -> Append (actual rows=N loops=N )
2342
+ -> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (actual rows=N loops=N )
2339
2343
Index Cond: (a = a.a)
2340
- -> Index Scan using ab_a1_b2_a_idx on ab_a1_b2 (actual rows=0 loops=2 )
2344
+ -> Index Scan using ab_a1_b2_a_idx on ab_a1_b2 (actual rows=N loops=N )
2341
2345
Index Cond: (a = a.a)
2342
- -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 (actual rows=0 loops=2 )
2346
+ -> Index Scan using ab_a1_b3_a_idx on ab_a1_b3 (actual rows=N loops=N )
2343
2347
Index Cond: (a = a.a)
2344
2348
-> Index Scan using ab_a2_b1_a_idx on ab_a2_b1 (never executed)
2345
2349
Index Cond: (a = a.a)
@@ -2359,16 +2363,16 @@ delete from lprt_a where a = 1;
2359
2363
select explain_parallel_append('select avg(ab.a) from ab inner join lprt_a a on ab.a = a.a where a.a in(1, 0, 0)');
2360
2364
explain_parallel_append
2361
2365
--------------------------------------------------------------------------------------------
2362
- Finalize Aggregate (actual rows=1 loops=1 )
2363
- -> Gather (actual rows=2 loops=1 )
2366
+ Finalize Aggregate (actual rows=N loops=N )
2367
+ -> Gather (actual rows=N loops=N )
2364
2368
Workers Planned: 1
2365
- Workers Launched:1
2366
- -> Partial Aggregate (actual rows=1 loops=2 )
2367
- -> Nested Loop (actual rows=0 loops=2 )
2368
- -> Parallel Seq Scan on lprt_a a (actual rows=50 loops=N)
2369
+ Workers Launched:N
2370
+ -> Partial Aggregate (actual rows=N loops=N )
2371
+ -> Nested Loop (actual rows=N loops=N )
2372
+ -> Parallel Seq Scan on lprt_a a (actual rows=N loops=N)
2369
2373
Filter: (a = ANY ('{1,0,0}'::integer[]))
2370
2374
Rows Removed by Filter: 1
2371
- -> Append (actual rows=0 loops=100 )
2375
+ -> Append (actual rows=N loops=N )
2372
2376
-> Index Scan using ab_a1_b1_a_idx on ab_a1_b1 (never executed)
2373
2377
Index Cond: (a = a.a)
2374
2378
-> Index Scan using ab_a1_b2_a_idx on ab_a1_b2 (never executed)