From bf51bff74872838ed1433ec128f4d0ebbcbd5cbf Mon Sep 17 00:00:00 2001 From: Wendell Jones Date: Tue, 7 Jul 2026 09:28:41 -0400 Subject: [PATCH] feat: add conditional VACUUM ANALYZE support with thresholds to performance monitor script --- scripts/Weekly-Performance-Monitor.ps1 | 82 ++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/scripts/Weekly-Performance-Monitor.ps1 b/scripts/Weekly-Performance-Monitor.ps1 index a34a7fff..336c2acc 100644 --- a/scripts/Weekly-Performance-Monitor.ps1 +++ b/scripts/Weekly-Performance-Monitor.ps1 @@ -51,7 +51,18 @@ param ( [switch]$EmailReport, [Parameter()] - [switch]$CompareWithPrevious + [switch]$CompareWithPrevious, + + [Parameter()] + [switch]$AutoVacuumAnalyze, + + [Parameter()] + [ValidateRange(1, [int]::MaxValue)] + [int]$DeadTupleThreshold = 100, + + [Parameter()] + [ValidateRange(0.01, 100.0)] + [double]$DeadTuplePercentThreshold = 0.02 ) # ============================================================================ @@ -158,15 +169,15 @@ function Get-IndexUsageStats { $query = @" SELECT schemaname, - tablename, - indexname, + relname AS tablename, + indexrelname, idx_scan, idx_tup_read, idx_tup_fetch, pg_size_pretty(pg_relation_size(indexrelid)) AS index_size FROM pg_stat_user_indexes WHERE schemaname IN ('library', 'users', 'authentication', 'displaypreferences', 'activitylog') -ORDER BY schemaname, tablename, idx_scan DESC; +ORDER BY schemaname, relname, idx_scan DESC; "@ try { @@ -193,7 +204,7 @@ function Get-TableSizeStats { $query = @" SELECT schemaname, - relname AS tablename, + relname, pg_size_pretty(pg_total_relation_size(schemaname||'.'||relname)) AS total_size, pg_size_pretty(pg_relation_size(schemaname||'.'||relname)) AS table_size, pg_size_pretty(pg_total_relation_size(schemaname||'.'||relname) - pg_relation_size(schemaname||'.'||relname)) AS index_size, @@ -221,6 +232,67 @@ ORDER BY pg_total_relation_size(schemaname||'.'||relname) DESC; } } +function Invoke-ConditionalVacuumAnalyze { + param( + [int]$MinDeadTuples, + [double]$MinDeadPercent + ) + + Write-ColorOutput "`nChecking for tables that need VACUUM ANALYZE..." -Color Cyan + Write-ColorOutput "Thresholds: dead tuples >= $MinDeadTuples and dead percent >= $MinDeadPercent" -Color Gray + + $tableQuery = @" +SELECT + format('%I.%I', schemaname, relname) AS qualified_table, + n_dead_tup, + ROUND(100.0 * n_dead_tup / NULLIF(n_live_tup, 0), 2) AS dead_pct +FROM pg_stat_user_tables +WHERE schemaname IN ('library', 'users', 'authentication', 'displaypreferences', 'activitylog') + AND n_live_tup > 0 + AND n_dead_tup >= $MinDeadTuples + AND (100.0 * n_dead_tup / NULLIF(n_live_tup, 0)) >= $MinDeadPercent +ORDER BY n_dead_tup DESC; +"@ + + try { + $tables = & $PSQL_PATH -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -t -A -F "|" -c $tableQuery 2>&1 + if ($LASTEXITCODE -ne 0) { + Write-ColorOutput "[ERROR] Failed to evaluate dead tuple thresholds: $tables" -Color Red + return $false + } + + $tableLines = @($tables | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) + if ($tableLines.Count -eq 0) { + Write-ColorOutput "[OK] No tables exceeded dead tuple thresholds" -Color Green + return $true + } + + Write-ColorOutput "Found $($tableLines.Count) table(s) requiring VACUUM ANALYZE" -Color Yellow + + foreach ($line in $tableLines) { + $parts = $line -split "\|", 3 + $qualifiedTable = $parts[0].Trim() + $deadTuples = if ($parts.Count -ge 2) { $parts[1].Trim() } else { "unknown" } + $deadPercent = if ($parts.Count -ge 3) { $parts[2].Trim() } else { "unknown" } + + Write-ColorOutput "Running VACUUM ANALYZE on $qualifiedTable (dead tuples: $deadTuples, dead percent: $deadPercent)" -Color Cyan + + $vacuumResult = & $PSQL_PATH -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -c "VACUUM (ANALYZE, VERBOSE) $qualifiedTable;" 2>&1 + if ($LASTEXITCODE -ne 0) { + Write-ColorOutput "[ERROR] VACUUM ANALYZE failed for $qualifiedTable : $vacuumResult" -Color Red + return $false + } + + Write-ColorOutput "[OK] VACUUM ANALYZE completed for $qualifiedTable" -Color Green + } + + return $true + } catch { + Write-ColorOutput "[ERROR] Conditional VACUUM ANALYZE failed: $_" -Color Red + return $false + } +} + function Compare-WithPrevious { param( [string]$CurrentReport,