feat(ops): add usage_logs partitioning check at deployment startup
Add CheckUsageLogsPartitioning function that: - Checks if usage_logs table is partitioned - Warns with prominent banner if not partitioned and rows > 100K - Provides actionable guidance for manual partition migration This helps operators identify performance risks early and take appropriate action before data volume causes issues.
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -432,3 +433,51 @@ func pgAdvisoryUnlock(ctx context.Context, db *sql.DB) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckUsageLogsPartitioning 检查 usage_logs 表是否已分区。
|
||||
// 如未分区且数据量较大,会输出醒目的警告提示运维人员考虑分区。
|
||||
func CheckUsageLogsPartitioning(ctx context.Context, db *sql.DB) {
|
||||
var isPartitioned bool
|
||||
err := db.QueryRowContext(ctx, `
|
||||
SELECT EXISTS(
|
||||
SELECT 1
|
||||
FROM pg_partitioned_table pt
|
||||
JOIN pg_class c ON c.oid = pt.partrelid
|
||||
WHERE c.relname = 'usage_logs'
|
||||
)
|
||||
`).Scan(&isPartitioned)
|
||||
if err != nil {
|
||||
// 查询失败时静默忽略,不影响启动
|
||||
return
|
||||
}
|
||||
|
||||
if isPartitioned {
|
||||
return
|
||||
}
|
||||
|
||||
// 检查数据量
|
||||
var rowCount int64
|
||||
err = db.QueryRowContext(ctx, `SELECT COUNT(*) FROM usage_logs`).Scan(&rowCount)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 数据量小于 10 万行时,分区不那么紧急
|
||||
if rowCount < 100000 {
|
||||
return
|
||||
}
|
||||
|
||||
// 数据量较大且未分区,输出醒目警告
|
||||
log.Printf("================================================================================")
|
||||
log.Printf("⚠️ PERFORMANCE WARNING: usage_logs table is NOT partitioned")
|
||||
log.Printf(" Current rows: %d (threshold: 100,000)", rowCount)
|
||||
log.Printf(" Large unpartitioned tables can cause:")
|
||||
log.Printf(" - Slow queries and dashboard latency")
|
||||
log.Printf(" - Index bloat and maintenance overhead")
|
||||
log.Printf(" - Longer backup/restore times")
|
||||
log.Printf(" Recommended actions:")
|
||||
log.Printf(" 1. Review migrations/035_usage_logs_partitioning.sql for manual migration")
|
||||
log.Printf(" 2. Plan partition conversion during low-traffic window")
|
||||
log.Printf(" 3. Ensure UsageCleanupConfig is enabled for automatic cleanup")
|
||||
log.Printf("================================================================================")
|
||||
}
|
||||
|
||||
@@ -362,7 +362,13 @@ func initializeDatabase(cfg *SetupConfig) error {
|
||||
|
||||
migrationCtx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
return repository.ApplyMigrations(migrationCtx, db)
|
||||
if err := repository.ApplyMigrations(migrationCtx, db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 检查 usage_logs 分区状态(仅在首次部署时提示)
|
||||
repository.CheckUsageLogsPartitioning(migrationCtx, db)
|
||||
return nil
|
||||
}
|
||||
|
||||
func createAdminUser(cfg *SetupConfig) (bool, string, error) {
|
||||
|
||||
Reference in New Issue
Block a user