Set analyze_interval on Security::Finding partitions

What does this MR do?

Sets analyze_interval: 1.day on Security::Finding's partitioned_by declaration so newly-rotated security_findings partitions get planner statistics promptly.

Why

Corrective action for INC-13566 (#624174). New security_findings leaf partitions were left with no planner stats (reltuples = -1) because the partition manager's post-rotation ANALYZE is gated on analyze_interval, which Security::Finding never set. With no stats, the planner picked a 483M-row parallel sequential scan, saturating patroni-sec.

On the 1.day interval

Summary: 1.day is a deliberate tighter override than CI's 3.days and the 1.week framework default (!252300). It is not a daily unconditional ANALYZE, it is cheap, and it caps the "new partition with no stats" danger window at ~24h instead of up to a week. Details below.

Full reasoning (cost, throttle, interval choice)
  • Fires when no manual ANALYZE ran in the interval. run_analyze_on_partitioned_table only fires when last_analyzed_at_within_interval? is false. That check reads pg_stat_get_last_analyze_time, which reflects manual ANALYZE only (last_analyze), not autovacuum's auto-analyze (last_autoanalyze). So a healthy autovacuum does not satisfy this throttle: the manual ANALYZE fires whenever nothing manual ran in the last 24h, independent of autovacuum. This is still bounded and cheap (see next point), but it is not skipped just because autovacuum is caught up.

  • ANALYZE is a bounded sample, not a scan. It samples ~300 × default_statistics_target rows regardless of the hundreds of millions of rows in a partition. security_findings is a bounded rolling window (retention via stale_after + partition detach), not an ever-growing table, so the parent-recurse ANALYZE covers a bounded set of partitions. Cheap relative to the unplanned seq scan it prevents.

  • 1.day caps the danger window. The risky moment is a freshly-rotated leaf with zero stats. Partitions rotate roughly every 1-2 weeks (100GB fill or stale_after), faster under volume spikes. 1.day bounds "cold partition, no stats" to ~24h; the 1.week default would let a new leaf sit statless for up to a week, which is the exact INC-13566 exposure window.

  • Caveat (post-rotation gap). The throttle reads last_analyze_time from the oldest partition as the table proxy, so a freshly-rotated leaf can still sit statless for up to the interval before the throttled parent-recurse ANALYZE next fires. 1.day shrinks that window rather than closing it; closing it properly (ANALYZE the just-created partition directly, bypassing the throttle) is tracked as a systemic follow-up in #624175.

The post-rotation ANALYZE runs ANALYZE (SKIP_LOCKED) on the parent (recurses all partitions), throttled to at most once per interval, with a 1h statement timeout.

Changes

  • ee/app/models/security/finding.rb: add analyze_interval: 1.day to partitioned_by.
  • ee/spec/models/security/finding_spec.rb: assert partitioning_strategy.analyze_interval == 1.day.
  • Closes #624174
  • Systemic follow-up: #624175 (default analyze_interval for all partitioned tables, !252300)
Edited by Gregory Havenga

Merge request reports

Loading
Loading