From e83bd2babd3ff08e794fa521c12f56e2b58443eb Mon Sep 17 00:00:00 2001 From: Jan Eitzinger Date: Fri, 13 Mar 2026 17:14:13 +0100 Subject: [PATCH] Consolidate migrations Entire-Checkpoint: a3dba4105838 --- internal/repository/migration.go | 7 +-- .../sqlite3/11_optimize-indexes.down.sql | 23 ++++++- .../sqlite3/11_optimize-indexes.up.sql | 61 +++++++++++++++++-- .../sqlite3/12_stats-covering-index.down.sql | 4 -- .../sqlite3/12_stats-covering-index.up.sql | 11 ---- .../13_status-covering-indexes.down.sql | 14 ----- .../sqlite3/13_status-covering-indexes.up.sql | 18 ------ .../14_running-partial-indexes.down.sql | 7 --- .../sqlite3/14_running-partial-indexes.up.sql | 18 ------ 9 files changed, 77 insertions(+), 86 deletions(-) delete mode 100644 internal/repository/migrations/sqlite3/12_stats-covering-index.down.sql delete mode 100644 internal/repository/migrations/sqlite3/12_stats-covering-index.up.sql delete mode 100644 internal/repository/migrations/sqlite3/13_status-covering-indexes.down.sql delete mode 100644 internal/repository/migrations/sqlite3/13_status-covering-indexes.up.sql delete mode 100644 internal/repository/migrations/sqlite3/14_running-partial-indexes.down.sql delete mode 100644 internal/repository/migrations/sqlite3/14_running-partial-indexes.up.sql diff --git a/internal/repository/migration.go b/internal/repository/migration.go index a2c09c1f..3a8f5e6c 100644 --- a/internal/repository/migration.go +++ b/internal/repository/migration.go @@ -21,14 +21,11 @@ import ( // is added to internal/repository/migrations/sqlite3/. // // Version history: -// - Version 14: Partial covering indexes for running jobs (tiny B-tree vs millions) -// - Version 13: Add covering indexes for status/dashboard queries (cluster, job_state, ...) -// - Version 12: Add covering index for stats queries (cluster, start_time, hpc_user, ...) -// - Version 11: Optimize job table indexes (reduce from ~78 to 48) +// - Version 11: Optimize job table indexes (reduce from ~78 to 48, add covering/partial indexes) // - Version 10: Node table // // Migration files are embedded at build time from the migrations directory. -const Version uint = 14 +const Version uint = 11 //go:embed migrations/* var migrationFiles embed.FS diff --git a/internal/repository/migrations/sqlite3/11_optimize-indexes.down.sql b/internal/repository/migrations/sqlite3/11_optimize-indexes.down.sql index 770b3c1a..c5c4553c 100644 --- a/internal/repository/migrations/sqlite3/11_optimize-indexes.down.sql +++ b/internal/repository/migrations/sqlite3/11_optimize-indexes.down.sql @@ -1,8 +1,26 @@ -- Migration 11 DOWN: Restore indexes from migration 09 --- ============================================================ +-- Drop partial indexes for running jobs +DROP INDEX IF EXISTS jobs_running_user_stats; +DROP INDEX IF EXISTS jobs_running_project_stats; +DROP INDEX IF EXISTS jobs_running_subcluster_stats; + +-- Drop covering status indexes, restore 3-col indexes +DROP INDEX IF EXISTS jobs_cluster_jobstate_user_stats; +DROP INDEX IF EXISTS jobs_cluster_jobstate_project_stats; +DROP INDEX IF EXISTS jobs_cluster_jobstate_subcluster_stats; + +CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_user + ON job (cluster, job_state, hpc_user); + +CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_project + ON job (cluster, job_state, project); + +-- Drop covering stats indexes +DROP INDEX IF EXISTS jobs_cluster_user_starttime_stats; +DROP INDEX IF EXISTS jobs_cluster_project_starttime_stats; + -- Recreate all removed indexes from migration 09 --- ============================================================ -- Cluster+Partition Filter Sorting CREATE INDEX IF NOT EXISTS jobs_cluster_partition_numnodes ON job (cluster, cluster_partition, num_nodes); @@ -52,5 +70,4 @@ CREATE INDEX IF NOT EXISTS jobs_cluster_arrayjobid_starttime ON job (cluster, ar -- Backup Indices For High Variety Columns CREATE INDEX IF NOT EXISTS jobs_duration ON job (duration); --- Optimize DB index usage PRAGMA optimize; diff --git a/internal/repository/migrations/sqlite3/11_optimize-indexes.up.sql b/internal/repository/migrations/sqlite3/11_optimize-indexes.up.sql index df838da6..666bcb7b 100644 --- a/internal/repository/migrations/sqlite3/11_optimize-indexes.up.sql +++ b/internal/repository/migrations/sqlite3/11_optimize-indexes.up.sql @@ -1,8 +1,8 @@ --- Migration 11: Remove overly specific table indexes formerly used in sorting --- When one or two indexed columns are used, sorting usually is fast --- Reduces from ~78 indexes to 48 for better write performance, --- reduced disk usage, and more reliable query planner decisions. --- Requires ANALYZE to be run after migration (done automatically on startup). +-- Migration 11: Optimize job table indexes +-- - Remove overly specific sorting indexes (reduces ~78 → 48) +-- - Add covering index for grouped stats queries +-- - Add covering indexes for status/dashboard queries +-- - Add partial covering indexes for running jobs (tiny B-tree) -- ============================================================ -- Drop SELECTED existing job indexes (from migrations 08/09) @@ -57,5 +57,54 @@ DROP INDEX IF EXISTS jobs_cluster_arrayjobid_starttime; -- Backup Indices For High Variety Columns DROP INDEX IF EXISTS jobs_duration; --- Optimize DB index usage +-- ============================================================ +-- Covering indexes for grouped stats queries +-- Column order: cluster (equality), hpc_user/project (GROUP BY), start_time (range scan) +-- Includes aggregated columns to avoid main table lookups entirely. +-- ============================================================ + +CREATE INDEX IF NOT EXISTS jobs_cluster_user_starttime_stats + ON job (cluster, hpc_user, start_time, duration, job_state, num_nodes, num_hwthreads, num_acc); + +CREATE INDEX IF NOT EXISTS jobs_cluster_project_starttime_stats + ON job (cluster, project, start_time, duration, job_state, num_nodes, num_hwthreads, num_acc); + +-- ============================================================ +-- Covering indexes for status/dashboard queries +-- Column order: cluster (equality), job_state (equality), grouping col, then aggregated columns +-- These indexes allow the status views to be served entirely from index scans. +-- ============================================================ + +-- Drop 3-col indexes that are subsumed by the covering indexes below +DROP INDEX IF EXISTS jobs_cluster_jobstate_user; +DROP INDEX IF EXISTS jobs_cluster_jobstate_project; + +CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_user_stats + ON job (cluster, job_state, hpc_user, duration, start_time, num_nodes, num_hwthreads, num_acc); + +CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_project_stats + ON job (cluster, job_state, project, duration, start_time, num_nodes, num_hwthreads, num_acc); + +CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_subcluster_stats + ON job (cluster, job_state, subcluster, duration, start_time, num_nodes, num_hwthreads, num_acc); + +-- ============================================================ +-- Partial covering indexes for running jobs +-- Only running jobs are in the B-tree, so these indexes are tiny compared to +-- the full-table indexes above. SQLite uses them when the query contains the +-- literal `job_state = 'running'` (not a parameter placeholder). +-- ============================================================ + +CREATE INDEX IF NOT EXISTS jobs_running_user_stats + ON job (cluster, hpc_user, num_nodes, num_hwthreads, num_acc, duration, start_time) + WHERE job_state = 'running'; + +CREATE INDEX IF NOT EXISTS jobs_running_project_stats + ON job (cluster, project, num_nodes, num_hwthreads, num_acc, duration, start_time) + WHERE job_state = 'running'; + +CREATE INDEX IF NOT EXISTS jobs_running_subcluster_stats + ON job (cluster, subcluster, num_nodes, num_hwthreads, num_acc, duration, start_time) + WHERE job_state = 'running'; + PRAGMA optimize; diff --git a/internal/repository/migrations/sqlite3/12_stats-covering-index.down.sql b/internal/repository/migrations/sqlite3/12_stats-covering-index.down.sql deleted file mode 100644 index 0d5e3865..00000000 --- a/internal/repository/migrations/sqlite3/12_stats-covering-index.down.sql +++ /dev/null @@ -1,4 +0,0 @@ -DROP INDEX IF EXISTS jobs_cluster_user_starttime_stats; -DROP INDEX IF EXISTS jobs_cluster_project_starttime_stats; - -PRAGMA optimize; diff --git a/internal/repository/migrations/sqlite3/12_stats-covering-index.up.sql b/internal/repository/migrations/sqlite3/12_stats-covering-index.up.sql deleted file mode 100644 index 2ddc8ffe..00000000 --- a/internal/repository/migrations/sqlite3/12_stats-covering-index.up.sql +++ /dev/null @@ -1,11 +0,0 @@ --- Migration 12: Add covering index for grouped stats queries --- Column order: cluster (equality), hpc_user (GROUP BY), start_time (range scan) --- Includes aggregated columns to avoid main table lookups entirely. - -CREATE INDEX IF NOT EXISTS jobs_cluster_user_starttime_stats - ON job (cluster, hpc_user, start_time, duration, job_state, num_nodes, num_hwthreads, num_acc); - -CREATE INDEX IF NOT EXISTS jobs_cluster_project_starttime_stats - ON job (cluster, project, start_time, duration, job_state, num_nodes, num_hwthreads, num_acc); - -PRAGMA optimize; diff --git a/internal/repository/migrations/sqlite3/13_status-covering-indexes.down.sql b/internal/repository/migrations/sqlite3/13_status-covering-indexes.down.sql deleted file mode 100644 index cc95b322..00000000 --- a/internal/repository/migrations/sqlite3/13_status-covering-indexes.down.sql +++ /dev/null @@ -1,14 +0,0 @@ --- Reverse migration 13: Remove covering status indexes, restore 3-col indexes - -DROP INDEX IF EXISTS jobs_cluster_jobstate_user_stats; -DROP INDEX IF EXISTS jobs_cluster_jobstate_project_stats; -DROP INDEX IF EXISTS jobs_cluster_jobstate_subcluster_stats; - --- Restore the original 3-col indexes -CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_user - ON job (cluster, job_state, hpc_user); - -CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_project - ON job (cluster, job_state, project); - - PRAGMA optimize; diff --git a/internal/repository/migrations/sqlite3/13_status-covering-indexes.up.sql b/internal/repository/migrations/sqlite3/13_status-covering-indexes.up.sql deleted file mode 100644 index 24189527..00000000 --- a/internal/repository/migrations/sqlite3/13_status-covering-indexes.up.sql +++ /dev/null @@ -1,18 +0,0 @@ --- Migration 13: Add covering indexes for status/dashboard queries --- Column order: cluster (equality), job_state (equality), grouping col, then aggregated columns --- These indexes allow the status views to be served entirely from index scans. - -CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_user_stats - ON job (cluster, job_state, hpc_user, duration, start_time, num_nodes, num_hwthreads, num_acc); - -CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_project_stats - ON job (cluster, job_state, project, duration, start_time, num_nodes, num_hwthreads, num_acc); - -CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_subcluster_stats - ON job (cluster, job_state, subcluster, duration, start_time, num_nodes, num_hwthreads, num_acc); - --- Drop 3-col indexes that are now subsumed by the covering indexes above -DROP INDEX IF EXISTS jobs_cluster_jobstate_user; -DROP INDEX IF EXISTS jobs_cluster_jobstate_project; - -PRAGMA optimize; diff --git a/internal/repository/migrations/sqlite3/14_running-partial-indexes.down.sql b/internal/repository/migrations/sqlite3/14_running-partial-indexes.down.sql deleted file mode 100644 index 39882baf..00000000 --- a/internal/repository/migrations/sqlite3/14_running-partial-indexes.down.sql +++ /dev/null @@ -1,7 +0,0 @@ --- Reverse migration 14: Drop partial indexes for running jobs - -DROP INDEX IF EXISTS jobs_running_user_stats; -DROP INDEX IF EXISTS jobs_running_project_stats; -DROP INDEX IF EXISTS jobs_running_subcluster_stats; - -PRAGMA optimize; diff --git a/internal/repository/migrations/sqlite3/14_running-partial-indexes.up.sql b/internal/repository/migrations/sqlite3/14_running-partial-indexes.up.sql deleted file mode 100644 index 8d7217d8..00000000 --- a/internal/repository/migrations/sqlite3/14_running-partial-indexes.up.sql +++ /dev/null @@ -1,18 +0,0 @@ --- Migration 14: Partial covering indexes for running jobs --- Only running jobs are in the B-tree, so these indexes are tiny compared to --- the full-table indexes from migration 13. SQLite uses them when the query --- contains the literal `job_state = 'running'` (not a parameter placeholder). - -CREATE INDEX IF NOT EXISTS jobs_running_user_stats - ON job (cluster, hpc_user, num_nodes, num_hwthreads, num_acc, duration, start_time) - WHERE job_state = 'running'; - -CREATE INDEX IF NOT EXISTS jobs_running_project_stats - ON job (cluster, project, num_nodes, num_hwthreads, num_acc, duration, start_time) - WHERE job_state = 'running'; - -CREATE INDEX IF NOT EXISTS jobs_running_subcluster_stats - ON job (cluster, subcluster, num_nodes, num_hwthreads, num_acc, duration, start_time) - WHERE job_state = 'running'; - -PRAGMA optimize;