diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..72edf64 --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,5 @@ +# Bolt's Journal + +## 2024-05-23 - Composite Index for Playlist Thumbnails +**Learning:** SQLite query optimizer needs explicit composite indexes for `WHERE x = ? ORDER BY y` clauses to avoid in-memory sorting, especially when used in correlated subqueries. +**Action:** Always check `ORDER BY` clauses in frequently run queries (like startup routines) and ensure covering indexes exist. diff --git a/src/main/database.js b/src/main/database.js index 03efb71..0d942b1 100644 --- a/src/main/database.js +++ b/src/main/database.js @@ -100,6 +100,7 @@ function initialize(app, customPath = null) { table.integer('sortOrder'); table.primary(['playlistId', 'videoId']); table.index('playlistId'); + table.index(['playlistId', 'sortOrder'], 'idx_playlist_video_sort'); }); } else { try { @@ -107,6 +108,11 @@ function initialize(app, customPath = null) { t.index('playlistId') ); } catch (e) {} + try { + await db.schema.alterTable('playlist_videos', (t) => + t.index(['playlistId', 'sortOrder'], 'idx_playlist_video_sort') + ); + } catch (e) {} } if (!(await db.schema.hasTable('artists'))) { diff --git a/test/integration/database_advanced.test.js b/test/integration/database_advanced.test.js index 320c895..630ccb8 100644 --- a/test/integration/database_advanced.test.js +++ b/test/integration/database_advanced.test.js @@ -123,4 +123,11 @@ describe('Advanced Database Logic', () => { expect(all.length).toBe(1); expect(all[0].name).toBe('Busy Artist'); }); + + test('should have composite index on playlist_videos', async () => { + const db = database.getDB(); + const indexes = await db.raw("PRAGMA index_list('playlist_videos')"); + const hasIndex = indexes.some(idx => idx.name === 'idx_playlist_video_sort'); + expect(hasIndex).toBe(true); + }); });