Skip to content

Commit 23a5bbf

Browse files
jhfclaude
andcommitted
test: Stabilize EXPLAIN plans with ANALYZE before plan generation
Add ANALYZE before EXPLAIN queries in test 303 to ensure the planner has current statistics rather than stale/auto-generated ones. This reduces (but doesn't fully eliminate) non-deterministic plan flips between database recreations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent dcb9e5e commit 23a5bbf

7 files changed

+329
-279
lines changed

test/expected/303_import_jobs_for_norway_small_history.out

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9001,6 +9001,9 @@ stats_summary | {
90019001
\x
90029002
\echo '--- Generating query plans for review ---'
90039003
--- Generating query plans for review ---
9004+
SET client_min_messages = error;
9005+
ANALYZE;
9006+
RESET client_min_messages;
90049007
\o test/expected/explain/303_import_jobs_for_norway_small_history-timepoints.txt
90059008
EXPLAIN (COSTS FALSE) SELECT * FROM public.timepoints;
90069009
\o test/expected/explain/303_import_jobs_for_norway_small_history-timesegments_def.txt
Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,56 @@
1-
QUERY PLAN
2-
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
1+
QUERY PLAN
2+
------------------------------------------------------------------------------------------------------------------------------------------
33
Hash Left Join
4-
Hash Cond: ((NULL::integer) = eia3.unit_id)
4+
Hash Cond: ((timeline_establishment.unit_type = tpa.unit_type) AND (timeline_establishment.unit_id = tpa.unit_id))
55
CTE external_idents_agg
66
-> HashAggregate
77
Group Key: ('establishment'::statistical_unit_type), ei.establishment_id
88
-> Append
99
-> Hash Join
10-
Hash Cond: (eit.id = ei.type_id)
11-
-> Seq Scan on external_ident_type eit
10+
Hash Cond: (ei.type_id = eit.id)
11+
-> Seq Scan on external_ident ei
12+
Filter: (establishment_id IS NOT NULL)
1213
-> Hash
13-
-> Seq Scan on external_ident ei
14-
Filter: (establishment_id IS NOT NULL)
14+
-> Seq Scan on external_ident_type eit
1515
-> Hash Join
16-
Hash Cond: (eit_1.id = ei_1.type_id)
17-
-> Seq Scan on external_ident_type eit_1
16+
Hash Cond: (ei_1.type_id = eit_1.id)
17+
-> Seq Scan on external_ident ei_1
18+
Filter: (legal_unit_id IS NOT NULL)
1819
-> Hash
19-
-> Seq Scan on external_ident ei_1
20-
Filter: (legal_unit_id IS NOT NULL)
20+
-> Seq Scan on external_ident_type eit_1
2121
-> Hash Join
22-
Hash Cond: (eit_2.id = ei_2.type_id)
23-
-> Seq Scan on external_ident_type eit_2
22+
Hash Cond: (ei_2.type_id = eit_2.id)
23+
-> Seq Scan on external_ident ei_2
24+
Filter: (enterprise_id IS NOT NULL)
2425
-> Hash
25-
-> Seq Scan on external_ident ei_2
26-
Filter: (enterprise_id IS NOT NULL)
26+
-> Seq Scan on external_ident_type eit_2
2727
-> Hash Join
28-
Hash Cond: (eit_3.id = ei_3.type_id)
29-
-> Seq Scan on external_ident_type eit_3
28+
Hash Cond: (ei_3.type_id = eit_3.id)
29+
-> Seq Scan on external_ident ei_3
30+
Filter: (enterprise_group_id IS NOT NULL)
3031
-> Hash
31-
-> Seq Scan on external_ident ei_3
32-
Filter: (enterprise_group_id IS NOT NULL)
32+
-> Seq Scan on external_ident_type eit_3
3333
-> Hash Left Join
34-
Hash Cond: ((NULL::integer) = eia2.unit_id)
35-
-> Hash Right Join
36-
Hash Cond: ((('establishment'::statistical_unit_type) = timeline_establishment.unit_type) AND (tfu.establishment_id = timeline_establishment.unit_id))
34+
Hash Cond: ((NULL::integer) = eia3.unit_id)
35+
-> Hash Left Join
36+
Hash Cond: ((NULL::integer) = eia2.unit_id)
37+
-> Hash Left Join
38+
Hash Cond: ((timeline_establishment.unit_type = eia1.unit_type) AND (timeline_establishment.unit_id = eia1.unit_id))
39+
-> Append
40+
-> Seq Scan on timeline_establishment
41+
-> Seq Scan on timeline_legal_unit
42+
-> Subquery Scan on "*SELECT* 3"
43+
-> Seq Scan on timeline_enterprise
44+
-> Hash
45+
-> CTE Scan on external_idents_agg eia1
46+
-> Hash
47+
-> CTE Scan on external_idents_agg eia2
48+
Filter: (unit_type = 'establishment'::statistical_unit_type)
49+
-> Hash
50+
-> CTE Scan on external_idents_agg eia3
51+
Filter: (unit_type = 'legal_unit'::statistical_unit_type)
52+
-> Hash
53+
-> Subquery Scan on tpa
3754
-> GroupAggregate
3855
Group Key: ('establishment'::statistical_unit_type), tfu.establishment_id
3956
-> Sort
@@ -63,21 +80,5 @@
6380
Filter: (enterprise_group_id IS NOT NULL)
6481
-> Hash
6582
-> Seq Scan on tag t_3
66-
-> Hash
67-
-> Hash Right Join
68-
Hash Cond: ((eia1.unit_type = timeline_establishment.unit_type) AND (eia1.unit_id = timeline_establishment.unit_id))
69-
-> CTE Scan on external_idents_agg eia1
70-
-> Hash
71-
-> Append
72-
-> Seq Scan on timeline_establishment
73-
-> Seq Scan on timeline_legal_unit
74-
-> Subquery Scan on "*SELECT* 3"
75-
-> Seq Scan on timeline_enterprise
76-
-> Hash
77-
-> CTE Scan on external_idents_agg eia2
78-
Filter: (unit_type = 'establishment'::statistical_unit_type)
79-
-> Hash
80-
-> CTE Scan on external_idents_agg eia3
81-
Filter: (unit_type = 'legal_unit'::statistical_unit_type)
82-
(79 rows)
83+
(80 rows)
8384

test/expected/explain/303_import_jobs_for_norway_small_history-timeline_enterprise_def.txt

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,48 +20,45 @@
2020
Disabled: true
2121
-> Hash Join
2222
Hash Cond: (t_1.unit_id = en_1.id)
23-
-> Index Scan using idx_timesegments_unit_daterange on timesegments t_1
24-
Index Cond: (unit_type = 'enterprise'::statistical_unit_type)
23+
-> Seq Scan on timesegments t_1
24+
Filter: (unit_type = 'enterprise'::statistical_unit_type)
2525
-> Hash
2626
-> Seq Scan on enterprise en_1
2727
-> GroupAggregate
2828
-> Sort
2929
Sort Key: timeline_legal_unit.legal_unit_id
30-
-> Index Scan using idx_timeline_legal_unit_enterprise_id on timeline_legal_unit
31-
Index Cond: (enterprise_id = en_1.id)
32-
Filter: ((t_1.valid_from < valid_until) AND (valid_from < t_1.valid_until))
30+
-> Seq Scan on timeline_legal_unit
31+
Filter: ((t_1.valid_from < valid_until) AND (valid_from < t_1.valid_until) AND (enterprise_id = en_1.id))
3332
-> GroupAggregate
3433
-> Sort
3534
Sort Key: timeline_establishment.establishment_id
36-
-> Index Scan using idx_timeline_establishment_enterprise_id on timeline_establishment
37-
Index Cond: (enterprise_id = en_1.id)
38-
Filter: ((t_1.valid_from < valid_until) AND (valid_from < t_1.valid_until))
35+
-> Seq Scan on timeline_establishment
36+
Filter: ((t_1.valid_from < valid_until) AND (valid_from < t_1.valid_until) AND (enterprise_id = en_1.id))
3937
-> Hash
4038
-> Hash Join
4139
Hash Cond: (t.unit_id = en.id)
42-
-> Index Scan using idx_timesegments_unit_daterange on timesegments t
43-
Index Cond: (unit_type = 'enterprise'::statistical_unit_type)
40+
-> Seq Scan on timesegments t
41+
Filter: (unit_type = 'enterprise'::statistical_unit_type)
4442
-> Hash
4543
-> Seq Scan on enterprise en
4644
-> Limit
47-
-> Incremental Sort
45+
-> Sort
4846
Sort Key: enplu_1.valid_from DESC, enplu_1.legal_unit_id DESC
49-
Presorted Key: enplu_1.valid_from
50-
-> Index Scan Backward using idx_timeline_legal_unit_valid_period on timeline_legal_unit enplu_1
51-
Index Cond: ((valid_from < t.valid_until) AND (valid_until > t.valid_from))
52-
Filter: (primary_for_enterprise AND (enterprise_id = en.id))
47+
-> Seq Scan on timeline_legal_unit enplu_1
48+
Filter: (primary_for_enterprise AND (t.valid_from < valid_until) AND (valid_from < t.valid_until) AND (enterprise_id = en.id))
5349
-> Limit
54-
-> Incremental Sort
50+
-> Sort
5551
Sort Key: enpes_1.valid_from DESC, enpes_1.establishment_id DESC
56-
Presorted Key: enpes_1.valid_from
57-
-> Index Scan Backward using idx_timeline_establishment_valid_period on timeline_establishment enpes_1
58-
Index Cond: ((valid_from < t.valid_until) AND (valid_until > t.valid_from))
59-
Filter: (primary_for_enterprise AND (enterprise_id = en.id))
60-
-> Limit
61-
-> Sort
62-
Sort Key: "*VALUES*".column3 DESC
63-
-> Values Scan on "*VALUES*"
64-
Filter: (column3 IS NOT NULL)
52+
-> Seq Scan on timeline_establishment enpes_1
53+
Filter: (primary_for_enterprise AND (t.valid_from < valid_until) AND (valid_from < t.valid_until) AND (enterprise_id = en.id))
54+
-> Memoize
55+
Cache Key: en.edit_comment, en.edit_by_user_id, en.edit_at, enplu_1.last_edit_comment, enplu_1.last_edit_by_user_id, enplu_1.last_edit_at, enpes_1.last_edit_comment, enpes_1.last_edit_by_user_id, enpes_1.last_edit_at
56+
Cache Mode: binary
57+
-> Limit
58+
-> Sort
59+
Sort Key: "*VALUES*".column3 DESC
60+
-> Values Scan on "*VALUES*"
61+
Filter: (column3 IS NOT NULL)
6562
SubPlan 2
6663
-> Aggregate
6764
-> Unique
@@ -104,5 +101,5 @@
104101
-> Result
105102
-> ProjectSet
106103
-> Result
107-
(104 rows)
104+
(101 rows)
108105

0 commit comments

Comments
 (0)