Throttle partitioned table ANALYZE on the parent's last analyze time
What does this MR do and why?
Database::PartitionManagementWorker throttles the whole-table ANALYZE of a partitioned table by the last ANALYZE time of its first partition. vacuumdb --analyze-in-stages, which gitlab-ctl pg-upgrade runs, analyzes every partition but never the partitioned parent, so after a major PostgreSQL upgrade the worker sees a fresh partition timestamp and skips the parent for up to the table's analyze_interval, leaving it without planner statistics.
The worker now checks the parent's own last_analyze, which PostgreSQL tracks for partitioned tables since version 14, and the pre-14 workaround comment goes with it. On GitLab.com nothing changes, because the worker's parent ANALYZE has always stamped the parent and its partitions together. On an instance where only the partitions were analyzed, the next worker run analyzes the parent once, which is the intended fix.
Resolves #631607 (closed).
How to set up and validate locally
-
Create a partitioned table with data and run what
gitlab-ctl pg-upgraderuns:CREATE TABLE p_t (id int, part int) PARTITION BY LIST (part); CREATE TABLE p_t_1 PARTITION OF p_t FOR VALUES IN (1); INSERT INTO p_t SELECT g, 1 FROM generate_series(1, 10000) g;vacuumdb -h <gdk-root>/postgresql -d <database> --analyze-in-stages -
SELECT relname, pg_stat_get_last_analyze_time(oid) FROM pg_class WHERE relname LIKE 'p\_t%';shows a timestamp forp_t_1andNULLforp_t. -
On
master,PartitionManager#sync_partitions(analyze: true)for a table in this state issues noANALYZE. On this branch it analyzes the parent. The new example inspec/lib/gitlab/database/partitioning/partition_manager_spec.rbsets up exactly this state and fails onmaster.
Supporting evidence
SQL repro on GDK PostgreSQL 17.8 (vacuumdb 17.8), scratch database, two list partitions with 10k rows:
| step | p_t (parent) last_analyze |
parent pg_statistic rows |
partitions last_analyze |
|---|---|---|---|
after vacuumdb -j2 --analyze-in-stages |
NULL | 0 | set |
after ANALYZE (SKIP_LOCKED) p_t |
set | 2 | set |
So the parent's own last_analyze is tracked on the supported version, and vacuumdb never sets it.
Regression spec in its committed form against master's partition_manager.rb (new example only):
1 example, 1 failure
Failure/Error: expect(control.occurrences).to include(analyze_regex)
# only eligibility query issued:
SELECT pg_stat_get_last_analyze_time('public._test_gitlab_main_my_model_example_table_1'::regclass)
# ANALYZE statements issued: 0Same spec with the fix, plus related files (worktree from master at da69c41d171b, PostgreSQL 17.8):
| check | result |
|---|---|
bundle exec rubocop on both changed files |
2 files inspected, no offenses detected |
bin/rspec spec/lib/gitlab/database/partitioning/partition_manager_spec.rb |
79 examples, 0 failures, 1 pending (pre-existing) |
bin/rspec spec/workers/database/partition_management_worker_spec.rb spec/lib/gitlab/database/partitioning_spec.rb |
31 examples, 0 failures, 1 pending |
Deploy impact: on GitLab.com the worker's parent ANALYZE has always stamped parent and partitions together, so their timestamps agree and nothing changes. Only a table whose partitions were analyzed on their own (manual ANALYZE of a partition, or a self-managed instance right after pg-upgrade) gets one extra parent ANALYZE on the next run, one table at a time under the existing 1 hour statement timeout.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist.