From e004d74d804e1116762a20e0c1e94aa2d5a9222e Mon Sep 17 00:00:00 2001 From: Alex Justesen <1144087+alexjustesen@users.noreply.github.com> Date: Wed, 27 Aug 2025 17:35:29 -0400 Subject: [PATCH 1/5] Add command to tune SQLite database for improved read performance --- app/Console/Commands/TuneSqliteForReads.php | 91 +++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 app/Console/Commands/TuneSqliteForReads.php diff --git a/app/Console/Commands/TuneSqliteForReads.php b/app/Console/Commands/TuneSqliteForReads.php new file mode 100644 index 0000000..057b02d --- /dev/null +++ b/app/Console/Commands/TuneSqliteForReads.php @@ -0,0 +1,91 @@ +error('This command is only available for SQLite databases.'); + return 1; + } + + $this->info('Tuning SQLite database for read performance...'); + + try { + // Enable WAL mode for better read performance + DB::statement('PRAGMA journal_mode=WAL'); + $this->info('✓ Journal mode set to WAL (Write-Ahead Logging)'); + + // Set cache size to 10,000 pages (approximately 40MB with default page size of 4KB) + DB::statement('PRAGMA cache_size=10000'); + $this->info('✓ Cache size set to 10,000 pages'); + + // Additional read optimizations + DB::statement('PRAGMA synchronous=NORMAL'); + $this->info('✓ Synchronous mode set to NORMAL'); + + DB::statement('PRAGMA temp_store=MEMORY'); + $this->info('✓ Temporary tables stored in memory'); + + DB::statement('PRAGMA mmap_size=268435456'); // 256MB + $this->info('✓ Memory-mapped I/O enabled (256MB)'); + + // Verify the settings + $this->newLine(); + $this->info('Current SQLite configuration:'); + + $journalMode = DB::selectOne('PRAGMA journal_mode'); + $this->line("Journal mode: {$journalMode->journal_mode}"); + + $cacheSize = DB::selectOne('PRAGMA cache_size'); + $this->line("Cache size: {$cacheSize->cache_size} pages"); + + $synchronous = DB::selectOne('PRAGMA synchronous'); + $this->line("Synchronous: {$synchronous->synchronous}"); + + $tempStore = DB::selectOne('PRAGMA temp_store'); + $this->line("Temp store: {$tempStore->temp_store}"); + + $mmapSize = DB::selectOne('PRAGMA mmap_size'); + $this->line("Memory-mapped size: " . number_format($mmapSize->mmap_size / 1024 / 1024, 1) . "MB"); + + $this->newLine(); + $this->info('SQLite database has been successfully tuned for read performance!'); + $this->comment('Note: These settings are applied immediately. For persistent configuration across'); + $this->comment('application restarts, set the following in your .env file:'); + $this->comment('DB_JOURNAL_MODE=WAL'); + $this->comment('DB_CACHE_SIZE=10000'); + $this->comment('DB_SYNCHRONOUS=NORMAL'); + $this->comment('DB_TEMP_STORE=MEMORY'); + $this->comment('DB_MMAP_SIZE=268435456'); + + } catch (\Exception $e) { + $this->error('Failed to tune SQLite database: ' . $e->getMessage()); + return 1; + } + + return 0; + } +} \ No newline at end of file From 10629696b74b70f2d0004bd59bc36a2cb4ec071f Mon Sep 17 00:00:00 2001 From: Alex Justesen <1144087+alexjustesen@users.noreply.github.com> Date: Wed, 27 Aug 2025 17:35:31 -0400 Subject: [PATCH 2/5] Add command to tune SQLite reads during database setup --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e5141df..56fb97b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,4 +40,5 @@ FROM base AS production USER www-data # Create the SQLite database, migrate the tables, and seed the data -RUN php -r "file_exists('database/database.sqlite') || touch('database/database.sqlite');" +RUN php -r "file_exists('database/database.sqlite') || touch('database/database.sqlite');" \ + && php artisan db:tune-sqlite-reads From e744008b8c1d3029384f5e41e6adc381a669090c Mon Sep 17 00:00:00 2001 From: Alex Justesen <1144087+alexjustesen@users.noreply.github.com> Date: Wed, 27 Aug 2025 17:35:44 -0400 Subject: [PATCH 3/5] Add database configuration step to installation process --- app/Console/Commands/Install.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/Console/Commands/Install.php b/app/Console/Commands/Install.php index 9e7c401..290faa7 100644 --- a/app/Console/Commands/Install.php +++ b/app/Console/Commands/Install.php @@ -39,6 +39,8 @@ public function handle() $this->ensureDatabaseExists(); + $this->configureDatabase(); + $this->copyEnvExample(); $this->createAppKey(); @@ -56,6 +58,15 @@ protected function ensureDatabaseExists(): void file_exists(database_path('database.sqlite')) || touch(database_path('database.sqlite')); } + protected function configureDatabase(): void + { + try { + $this->call('db:tune-sqlite-reads'); + } catch (\Throwable $th) { + $this->fail('❌ There was an issue tuning SQLite reads, check the logs.'); + } + } + /** * Copy the .env.example file to .env. */ From 67742fe57ab5184795c343faf08ce6b18fdfbbbc Mon Sep 17 00:00:00 2001 From: Alex Justesen <1144087+alexjustesen@users.noreply.github.com> Date: Wed, 27 Aug 2025 17:35:51 -0400 Subject: [PATCH 4/5] Enhance SQLite configuration with journal mode, synchronous settings, cache size, and temporary storage options --- config/database.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/config/database.php b/config/database.php index 125949e..c2ea294 100644 --- a/config/database.php +++ b/config/database.php @@ -38,8 +38,11 @@ 'prefix' => '', 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), 'busy_timeout' => null, - 'journal_mode' => null, - 'synchronous' => null, + 'journal_mode' => env('DB_JOURNAL_MODE', 'WAL'), + 'synchronous' => env('DB_SYNCHRONOUS', 'NORMAL'), + 'cache_size' => env('DB_CACHE_SIZE', 10000), + 'temp_store' => env('DB_TEMP_STORE', 'MEMORY'), + 'mmap_size' => env('DB_MMAP_SIZE', 268435456), // 256MB ], 'mysql' => [ From ac5383560ffd4f1d0fbedbce68463015e9e345d5 Mon Sep 17 00:00:00 2001 From: Alex Justesen <1144087+alexjustesen@users.noreply.github.com> Date: Wed, 27 Aug 2025 17:37:29 -0400 Subject: [PATCH 5/5] lint --- app/Console/Commands/TuneSqliteForReads.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/Console/Commands/TuneSqliteForReads.php b/app/Console/Commands/TuneSqliteForReads.php index 057b02d..7641bd0 100644 --- a/app/Console/Commands/TuneSqliteForReads.php +++ b/app/Console/Commands/TuneSqliteForReads.php @@ -28,6 +28,7 @@ public function handle() { if (config('database.default') !== 'sqlite') { $this->error('This command is only available for SQLite databases.'); + return 1; } @@ -55,21 +56,21 @@ public function handle() // Verify the settings $this->newLine(); $this->info('Current SQLite configuration:'); - + $journalMode = DB::selectOne('PRAGMA journal_mode'); $this->line("Journal mode: {$journalMode->journal_mode}"); - + $cacheSize = DB::selectOne('PRAGMA cache_size'); $this->line("Cache size: {$cacheSize->cache_size} pages"); - + $synchronous = DB::selectOne('PRAGMA synchronous'); $this->line("Synchronous: {$synchronous->synchronous}"); - + $tempStore = DB::selectOne('PRAGMA temp_store'); $this->line("Temp store: {$tempStore->temp_store}"); - + $mmapSize = DB::selectOne('PRAGMA mmap_size'); - $this->line("Memory-mapped size: " . number_format($mmapSize->mmap_size / 1024 / 1024, 1) . "MB"); + $this->line('Memory-mapped size: '.number_format($mmapSize->mmap_size / 1024 / 1024, 1).'MB'); $this->newLine(); $this->info('SQLite database has been successfully tuned for read performance!'); @@ -82,10 +83,11 @@ public function handle() $this->comment('DB_MMAP_SIZE=268435456'); } catch (\Exception $e) { - $this->error('Failed to tune SQLite database: ' . $e->getMessage()); + $this->error('Failed to tune SQLite database: '.$e->getMessage()); + return 1; } return 0; } -} \ No newline at end of file +}