From 0e27624d73d018772ad38204dc3ae5274e8e8e19 Mon Sep 17 00:00:00 2001 From: Jan Eitzinger Date: Thu, 12 Mar 2026 20:12:49 +0100 Subject: [PATCH] Add flag to optimize db. Remove ANALYZE on startup. Entire-Checkpoint: d49917ff4b10 --- cmd/cc-backend/cli.go | 3 ++- cmd/cc-backend/main.go | 14 ++++++++++++++ internal/repository/dbConnection.go | 8 -------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/cmd/cc-backend/cli.go b/cmd/cc-backend/cli.go index 9ee56cb2..47f534be 100644 --- a/cmd/cc-backend/cli.go +++ b/cmd/cc-backend/cli.go @@ -11,7 +11,7 @@ import "flag" var ( flagReinitDB, flagInit, flagServer, flagSyncLDAP, flagGops, flagMigrateDB, flagRevertDB, - flagForceDB, flagDev, flagVersion, flagLogDateTime, flagApplyTags bool + flagForceDB, flagDev, flagVersion, flagLogDateTime, flagApplyTags, flagOptimizeDB bool flagNewUser, flagDelUser, flagGenJWT, flagConfigFile, flagImportJob, flagLogLevel string ) @@ -27,6 +27,7 @@ func cliInit() { flag.BoolVar(&flagRevertDB, "revert-db", false, "Migrate database to previous version and exit") flag.BoolVar(&flagApplyTags, "apply-tags", false, "Run taggers on all completed jobs and exit") flag.BoolVar(&flagForceDB, "force-db", false, "Force database version, clear dirty flag and exit") + flag.BoolVar(&flagOptimizeDB, "optimize-db", false, "Optimize database: run VACUUM to reclaim space, then ANALYZE to update query planner statistics") flag.BoolVar(&flagLogDateTime, "logdate", false, "Set this flag to add date and time to log messages") flag.StringVar(&flagConfigFile, "config", "./config.json", "Specify alternative path to `config.json`") flag.StringVar(&flagNewUser, "add-user", "", "Add a new user. Argument format: :[admin,support,manager,api,user]:") diff --git a/cmd/cc-backend/main.go b/cmd/cc-backend/main.go index 5e6eea9a..9e1ea8aa 100644 --- a/cmd/cc-backend/main.go +++ b/cmd/cc-backend/main.go @@ -509,6 +509,20 @@ func run() error { return err } + // Optimize database if requested + if flagOptimizeDB { + db := repository.GetConnection() + cclog.Print("Running VACUUM to reclaim space and defragment database...") + if _, err := db.DB.Exec("VACUUM"); err != nil { + return fmt.Errorf("VACUUM failed: %w", err) + } + cclog.Print("Running ANALYZE to update query planner statistics...") + if _, err := db.DB.Exec("ANALYZE"); err != nil { + return fmt.Errorf("ANALYZE failed: %w", err) + } + cclog.Exitf("OptimizeDB Success: Database '%s' optimized (VACUUM + ANALYZE).\n", config.Keys.DB) + } + // Handle user commands (add, delete, sync, JWT) if err := handleUserCommands(); err != nil { return err diff --git a/internal/repository/dbConnection.go b/internal/repository/dbConnection.go index cda7981a..23a19c93 100644 --- a/internal/repository/dbConnection.go +++ b/internal/repository/dbConnection.go @@ -49,14 +49,6 @@ func setupSqlite(db *sql.DB, cfg *RepositoryConfig) error { } } - // Update query planner statistics so SQLite picks optimal indexes. - // Without this, SQLite guesses row distributions and often chooses wrong - // indexes for queries with IN clauses + ORDER BY, causing full table sorts - // in temp B-trees instead of using covering indexes. - if _, err := db.Exec("ANALYZE"); err != nil { - cclog.Warnf("Failed to run ANALYZE: %v", err) - } - return nil }