Prepare async index on merge_request_metrics for deploy metrics
What does this MR do and why?
Deployments::UpdateEnvironmentWorker runs an UPDATE on
merge_request_metrics on every successful production deployment. It
filters not-yet-deployed merge requests by target_project_id,
target_branch, and a merged_at range, but no index supports the
selective part, so the planner scans every merged MR on the branch. In a
recent GitLab.com slow-query sample it was the single biggest
contributor (about 6,066 seconds of database time).
This MR prepares a partial async index:
CREATE INDEX index_mr_metrics_on_project_merged_at_not_deployed
ON merge_request_metrics (target_project_id, merged_at)
WHERE first_deployed_to_production_at IS NULL;merge_request_metrics is over_limit, so the partial
WHERE first_deployed_to_production_at IS NULL predicate matters: it
covers only not-yet-deployed rows, and a row leaves that set permanently
once deployed, keeping the index small.
This is the async-prepare step. A follow-up MR will create the index
synchronously with add_concurrent_index and drop the near-useless
index_merge_request_metrics_on_first_deployed_to_production_at to keep
the table's index count flat.
Issue: #628635 (closed)
Migration output
Up:
main: == 20260910120000 PrepareAsyncIndexMrMetricsOnProjectMergedAtNotDeployed: migrating
main: == 20260910120000 PrepareAsyncIndexMrMetricsOnProjectMergedAtNotDeployed: migrated (0.1173s)Down:
main: == 20260910120000 PrepareAsyncIndexMrMetricsOnProjectMergedAtNotDeployed: reverting
main: == 20260910120000 PrepareAsyncIndexMrMetricsOnProjectMergedAtNotDeployed: revertedPrepared index definition recorded in postgres_async_indexes:
CREATE INDEX CONCURRENTLY "index_mr_metrics_on_project_merged_at_not_deployed" ON "merge_request_metrics" ("target_project_id", "merged_at") WHERE first_deployed_to_production_at IS NULL