Skip to content

Commit 6cd68d8

Browse files
committed
graph: Improve estimate of how much of a table pruning will remove
Our current estimate is way too naive and causes a lot of unnecessary table rebuilds. Using statistics from pg_stats should improve that
1 parent 86c2e69 commit 6cd68d8

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

graph/src/components/store/mod.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,11 +1099,22 @@ impl PruneRequest {
10991099
return None;
11001100
}
11011101

1102-
// Estimate how much data we will throw away; we assume that
1103-
// entity versions are distributed evenly across all blocks so
1104-
// that `history_pct` will tell us how much of that data pruning
1105-
// will remove.
1106-
let removal_ratio = self.history_pct(stats) * (1.0 - stats.ratio);
1102+
let removal_ratio = if stats.block_range_upper.is_empty()
1103+
|| ENV_VARS.store.prune_disable_range_bound_estimation
1104+
{
1105+
// Estimate how much data we will throw away; we assume that
1106+
// entity versions are distributed evenly across all blocks so
1107+
// that `history_pct` will tell us how much of that data pruning
1108+
// will remove.
1109+
self.history_pct(stats) * (1.0 - stats.ratio)
1110+
} else {
1111+
// This estimate is more accurate than the one above since it
1112+
// does not assume anything about the distribution of entities
1113+
// and versions but uses the estimates from Postgres statistics.
1114+
// Of course, we can only use it if we have statistics
1115+
self.remove_pct_from_bounds(stats)
1116+
};
1117+
11071118
if removal_ratio >= self.rebuild_threshold {
11081119
Some(PruningStrategy::Rebuild)
11091120
} else if removal_ratio >= self.delete_threshold {
@@ -1128,6 +1139,18 @@ impl PruneRequest {
11281139
1.0 - self.history_blocks as f64 / total_blocks as f64
11291140
}
11301141
}
1142+
1143+
/// Return the fraction of entities that we will remove according to the
1144+
/// histogram bounds in `stats`. That fraction can be estimated as the
1145+
/// fraction of histogram buckets that end before `self.earliest_block`
1146+
fn remove_pct_from_bounds(&self, stats: &VersionStats) -> f64 {
1147+
stats
1148+
.block_range_upper
1149+
.iter()
1150+
.filter(|b| **b <= self.earliest_block)
1151+
.count() as f64
1152+
/ stats.block_range_upper.len() as f64
1153+
}
11311154
}
11321155

11331156
/// Represents an item retrieved from an

graph/src/env/store.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ pub struct EnvVarsStore {
114114
/// For how many prune runs per deployment to keep status information.
115115
/// Set by `GRAPH_STORE_HISTORY_KEEP_STATUS`. The default is 5
116116
pub prune_keep_history: usize,
117+
/// Temporary switch to disable range bound estimation for pruning.
118+
/// Set by `GRAPH_STORE_PRUNE_DISABLE_RANGE_BOUND_ESTIMATION`.
119+
/// Defaults to false. Remove after 2025-07-15
120+
pub prune_disable_range_bound_estimation: bool,
117121
/// How long to accumulate changes into a batch before a write has to
118122
/// happen. Set by the environment variable
119123
/// `GRAPH_STORE_WRITE_BATCH_DURATION` in seconds. The default is 300s.
@@ -188,6 +192,7 @@ impl TryFrom<InnerStore> for EnvVarsStore {
188192
delete_threshold: x.delete_threshold.0,
189193
history_slack_factor: x.history_slack_factor.0,
190194
prune_keep_history: x.prune_keep_status,
195+
prune_disable_range_bound_estimation: x.prune_disable_range_bound_estimation,
191196
write_batch_duration: Duration::from_secs(x.write_batch_duration_in_secs),
192197
write_batch_size: x.write_batch_size * 1_000,
193198
create_gin_indexes: x.create_gin_indexes,
@@ -263,6 +268,11 @@ pub struct InnerStore {
263268
history_slack_factor: HistorySlackF64,
264269
#[envconfig(from = "GRAPH_STORE_HISTORY_KEEP_STATUS", default = "5")]
265270
prune_keep_status: usize,
271+
#[envconfig(
272+
from = "GRAPH_STORE_PRUNE_DISABLE_RANGE_BOUND_ESTIMATION",
273+
default = "false"
274+
)]
275+
prune_disable_range_bound_estimation: bool,
266276
#[envconfig(from = "GRAPH_STORE_WRITE_BATCH_DURATION", default = "300")]
267277
write_batch_duration_in_secs: u64,
268278
#[envconfig(from = "GRAPH_STORE_WRITE_BATCH_SIZE", default = "10000")]

0 commit comments

Comments
 (0)