Add postgres_index_bloat_estimate SQL function

What does this MR do and why?

The view postgres_index_bloat_estimates was producing underperforming plans on instances where catalog statistics have drifted, causing single-index bloat lookups (the only way the application uses it) to timeout.

The new postgres_index_bloat_estimate(schema, idxname) function:

  • Anchors on pg_class with the index name as a parameter, so the outer scan is a direct seek via pg_class_relname_nsp_index.
  • Uses CROSS JOIN LATERAL for the bloat math instead of nested subqueries with a ProjectSet barrier, so predicates can be pushed all the way through.
  • Splits the pg_stats join into two pushdown-friendly lookups (one against the table for regular columns, one against the index for expression columns) so pg_stats's internal joins can use index seeks instead of scanning thousands of pg_class rows.

PostgresIndex#bloat_size now calls the function directly, removing the PostgresIndexBloatEstimate model entirely. The view is left in place; dropping it is a separate MR / post-deploy migration.

For some reason the first one reports more buffers used (~12 MiB vs ~1.40 MiB). 🤔 still way better than the existing query - https://console.postgres.ai/gitlab/gitlab-production-main/sessions/52120/commands/153536.

References

How to set up and validate locally

  1. Create the function on DBLab clone
  2. Verify it returns same results as the existing `` view
    select *,
    postgres_index_bloat_estimate('public', split_part(identifier, '.', 2)),
    bloat_size_bytes = postgres_index_bloat_estimate('public', split_part(identifier, '.', 2)) as equal
    from postgres_index_bloat_estimates order by bloat_size_bytes desc limit 2

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Krasimir Angelov

Merge request reports

Loading