From 72a93a5449bcd435bbb30fa5dc7c53a4da70fdc0 Mon Sep 17 00:00:00 2001 From: Deluan Date: Tue, 25 Nov 2025 19:48:53 -0500 Subject: [PATCH] feat: add DevOptimizeDB flag to control SQLite optimization Added a new DevOptimizeDB configuration flag (default true) that controls whether SQLite PRAGMA OPTIMIZE and ANALYZE commands are executed. This allows disabling database optimization operations for debugging or testing purposes. The flag guards optimization commands in: - db/db.go: Initial connection, post-migration, and shutdown optimization - persistence/library_repository.go: Post-scan optimization - db/migrations/migration.go: ANALYZE during forced full rescans Set ND_DEVOPTIMIZEDB=false to disable all database optimization commands. --- conf/configuration.go | 4 +++- db/db.go | 15 ++++++++++----- db/migrations/migration.go | 11 +++++++---- persistence/library_repository.go | 4 +++- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/conf/configuration.go b/conf/configuration.go index 58ba2c5f9..498a28955 100644 --- a/conf/configuration.go +++ b/conf/configuration.go @@ -132,6 +132,7 @@ type configOptions struct { DevEnablePluginsInsights bool DevPluginCompilationTimeout time.Duration DevExternalArtistFetchMultiplier float64 + DevOptimizeDB bool } type scannerOptions struct { @@ -438,7 +439,7 @@ func validatePurgeMissingOption() error { } } if !valid { - err := fmt.Errorf("Invalid Scanner.PurgeMissing value: '%s'. Must be one of: %v", Server.Scanner.PurgeMissing, allowedValues) + err := fmt.Errorf("invalid Scanner.PurgeMissing value: '%s'. Must be one of: %v", Server.Scanner.PurgeMissing, allowedValues) log.Error(err.Error()) Server.Scanner.PurgeMissing = consts.PurgeMissingNever return err @@ -630,6 +631,7 @@ func setViperDefaults() { viper.SetDefault("devenablepluginsinsights", true) viper.SetDefault("devplugincompilationtimeout", time.Minute) viper.SetDefault("devexternalartistfetchmultiplier", 1.5) + viper.SetDefault("devoptimizedb", true) } func init() { diff --git a/db/db.go b/db/db.go index cb1ebd9e3..71bc082b2 100644 --- a/db/db.go +++ b/db/db.go @@ -45,10 +45,12 @@ func Db() *sql.DB { if err != nil { log.Fatal("Error opening database", err) } - _, err = db.Exec("PRAGMA optimize=0x10002") - if err != nil { - log.Error("Error applying PRAGMA optimize", err) - return nil + if conf.Server.DevOptimizeDB { + _, err = db.Exec("PRAGMA optimize=0x10002") + if err != nil { + log.Error("Error applying PRAGMA optimize", err) + return nil + } } return db }) @@ -99,7 +101,7 @@ func Init(ctx context.Context) func() { log.Fatal(ctx, "Failed to apply new migrations", err) } - if hasSchemaChanges { + if hasSchemaChanges && conf.Server.DevOptimizeDB { log.Debug(ctx, "Applying PRAGMA optimize after schema changes") _, err = db.ExecContext(ctx, "PRAGMA optimize") if err != nil { @@ -114,6 +116,9 @@ func Init(ctx context.Context) func() { // Optimize runs PRAGMA optimize on each connection in the pool func Optimize(ctx context.Context) { + if !conf.Server.DevOptimizeDB { + return + } numConns := Db().Stats().OpenConnections if numConns == 0 { log.Debug(ctx, "No open connections to optimize") diff --git a/db/migrations/migration.go b/db/migrations/migration.go index 8d8f8a91e..fde6f5817 100644 --- a/db/migrations/migration.go +++ b/db/migrations/migration.go @@ -7,6 +7,7 @@ import ( "strings" "sync" + "github.com/navidrome/navidrome/conf" "github.com/navidrome/navidrome/consts" ) @@ -21,11 +22,13 @@ func notice(tx *sql.Tx, msg string) { // Call this in migrations that requires a full rescan func forceFullRescan(tx *sql.Tx) error { // If a full scan is required, most probably the query optimizer is outdated, so we run `analyze`. - _, err := tx.Exec(`ANALYZE;`) - if err != nil { - return err + if conf.Server.DevOptimizeDB { + _, err := tx.Exec(`ANALYZE;`) + if err != nil { + return err + } } - _, err = tx.Exec(fmt.Sprintf(` + _, err := tx.Exec(fmt.Sprintf(` INSERT OR REPLACE into property (id, value) values ('%s', '1'); `, consts.FullScanAfterMigrationFlagKey)) return err diff --git a/persistence/library_repository.go b/persistence/library_repository.go index 5621e1719..9349f3c4c 100644 --- a/persistence/library_repository.go +++ b/persistence/library_repository.go @@ -179,7 +179,9 @@ func (r *libraryRepository) ScanEnd(id int) error { // https://www.sqlite.org/pragma.html#pragma_optimize // Use mask 0x10000 to check table sizes without running ANALYZE // Running ANALYZE can cause query planner issues with expression-based collation indexes - _, err = r.executeSQL(Expr("PRAGMA optimize=0x10000;")) + if conf.Server.DevOptimizeDB { + _, err = r.executeSQL(Expr("PRAGMA optimize=0x10000;")) + } return err }