mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2026-03-15 04:17:30 +01:00
Add migration with alternative reduces index set
Entire-Checkpoint: af7afc9a29ff
This commit is contained in:
@@ -22,3 +22,26 @@
|
||||
{"time":"2026-03-11T05:08:52.825155+01:00","level":"INFO","msg":"committed changes to shadow branch","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"checkpoint","agent":"claude-code","shadow_branch":"entire/1cf9920-e3b0c4"}
|
||||
{"time":"2026-03-11T05:08:52.825161+01:00","level":"INFO","msg":"checkpoint saved","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"checkpoint","agent":"claude-code","strategy":"manual-commit","checkpoint_type":"session","checkpoint_count":2,"modified_files":1,"new_files":0,"deleted_files":0,"shadow_branch":"entire/1cf9920-e3b0c4","branch_created":false}
|
||||
{"time":"2026-03-11T05:08:52.82522+01:00","level":"INFO","msg":"phase transition","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"session","agent":"claude-code","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","event":"TurnEnd","from":"active","to":"idle"}
|
||||
{"time":"2026-03-11T05:31:33.173849+01:00","level":"INFO","msg":"turn-start","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"lifecycle","agent":"claude-code","event":"TurnStart","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","session_ref":"/Users/jan/.claude/projects/-Users-jan-prg-CC-cc-backend/42401d2e-7d1c-4c0e-abe6-356cb2d48747.jsonl"}
|
||||
{"time":"2026-03-11T05:31:33.40187+01:00","level":"INFO","msg":"phase transition","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"session","agent":"claude-code","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","event":"TurnStart","from":"idle","to":"active"}
|
||||
{"time":"2026-03-11T05:31:49.964342+01:00","level":"INFO","msg":"subagent started","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"lifecycle","agent":"claude-code","event":"SubagentStart","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","tool_use_id":"toolu_01MJqptZJ5SuaZVBxAKZ1svX","transcript":"/Users/jan/.claude/projects/-Users-jan-prg-CC-cc-backend/42401d2e-7d1c-4c0e-abe6-356cb2d48747.jsonl"}
|
||||
{"time":"2026-03-11T05:31:55.403816+01:00","level":"INFO","msg":"subagent started","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"lifecycle","agent":"claude-code","event":"SubagentStart","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","tool_use_id":"toolu_01FTC59ufvgXt3VSQCNwf6FA","transcript":"/Users/jan/.claude/projects/-Users-jan-prg-CC-cc-backend/42401d2e-7d1c-4c0e-abe6-356cb2d48747.jsonl"}
|
||||
{"time":"2026-03-11T05:32:17.136258+01:00","level":"INFO","msg":"subagent completed","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"lifecycle","agent":"claude-code","event":"SubagentEnd","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","tool_use_id":"toolu_01FTC59ufvgXt3VSQCNwf6FA","agent_id":"a1ede6e4db46fa8db"}
|
||||
{"time":"2026-03-11T05:32:17.410446+01:00","level":"INFO","msg":"committed task checkpoint to shadow branch","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"checkpoint","agent":"claude-code","shadow_branch":"entire/eba3995-e3b0c4"}
|
||||
{"time":"2026-03-11T05:32:17.410453+01:00","level":"INFO","msg":"task checkpoint saved","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"checkpoint","agent":"claude-code","strategy":"manual-commit","checkpoint_type":"task","checkpoint_uuid":"","tool_use_id":"toolu_01FTC59ufvgXt3VSQCNwf6FA","subagent_type":"Explore","modified_files":3,"new_files":0,"deleted_files":0,"shadow_branch":"entire/eba3995-e3b0c4","branch_created":false}
|
||||
{"time":"2026-03-11T05:32:51.785996+01:00","level":"INFO","msg":"subagent completed","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"lifecycle","agent":"claude-code","event":"SubagentEnd","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","tool_use_id":"toolu_01MJqptZJ5SuaZVBxAKZ1svX","agent_id":"a97d0003ebdc3eccd"}
|
||||
{"time":"2026-03-11T05:32:52.089909+01:00","level":"INFO","msg":"committed task checkpoint to shadow branch","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"checkpoint","agent":"claude-code","shadow_branch":"entire/eba3995-e3b0c4"}
|
||||
{"time":"2026-03-11T05:32:52.089916+01:00","level":"INFO","msg":"task checkpoint saved","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"checkpoint","agent":"claude-code","strategy":"manual-commit","checkpoint_type":"task","checkpoint_uuid":"","tool_use_id":"toolu_01MJqptZJ5SuaZVBxAKZ1svX","subagent_type":"Explore","modified_files":3,"new_files":0,"deleted_files":0,"shadow_branch":"entire/eba3995-e3b0c4","branch_created":false}
|
||||
{"time":"2026-03-11T05:34:41.346156+01:00","level":"INFO","msg":"subagent started","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"lifecycle","agent":"claude-code","event":"SubagentStart","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","tool_use_id":"toolu_01MERmbUXd1oS8d2m7sVmGXr","transcript":"/Users/jan/.claude/projects/-Users-jan-prg-CC-cc-backend/42401d2e-7d1c-4c0e-abe6-356cb2d48747.jsonl"}
|
||||
{"time":"2026-03-11T05:36:59.651293+01:00","level":"INFO","msg":"subagent completed","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"lifecycle","agent":"claude-code","event":"SubagentEnd","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","tool_use_id":"toolu_01MERmbUXd1oS8d2m7sVmGXr","agent_id":"a4e4f76de8a1612f2"}
|
||||
{"time":"2026-03-11T05:37:00.005222+01:00","level":"INFO","msg":"committed task checkpoint to shadow branch","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"checkpoint","agent":"claude-code","shadow_branch":"entire/eba3995-e3b0c4"}
|
||||
{"time":"2026-03-11T05:37:00.005229+01:00","level":"INFO","msg":"task checkpoint saved","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"checkpoint","agent":"claude-code","strategy":"manual-commit","checkpoint_type":"task","checkpoint_uuid":"","tool_use_id":"toolu_01MERmbUXd1oS8d2m7sVmGXr","subagent_type":"Plan","modified_files":3,"new_files":0,"deleted_files":0,"shadow_branch":"entire/eba3995-e3b0c4","branch_created":false}
|
||||
{"time":"2026-03-11T05:41:52.270916+01:00","level":"INFO","msg":"turn-end","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"lifecycle","agent":"claude-code","event":"TurnEnd","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","session_ref":"/Users/jan/.claude/projects/-Users-jan-prg-CC-cc-backend/42401d2e-7d1c-4c0e-abe6-356cb2d48747.jsonl"}
|
||||
{"time":"2026-03-11T05:41:52.650259+01:00","level":"INFO","msg":"no files modified during session, skipping checkpoint","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"lifecycle","agent":"claude-code"}
|
||||
{"time":"2026-03-11T05:41:52.650334+01:00","level":"INFO","msg":"phase transition","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"session","agent":"claude-code","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","event":"TurnEnd","from":"active","to":"idle"}
|
||||
{"time":"2026-03-11T05:41:52.728326+01:00","level":"INFO","msg":"session-end","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"lifecycle","agent":"claude-code","event":"SessionEnd","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747"}
|
||||
{"time":"2026-03-11T05:41:52.72837+01:00","level":"INFO","msg":"phase transition","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"session","agent":"claude-code","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","event":"SessionStop","from":"idle","to":"ended"}
|
||||
{"time":"2026-03-11T05:41:52.79542+01:00","level":"INFO","msg":"session-start","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"lifecycle","agent":"claude-code","event":"SessionStart","session_id":"c31c699a-f492-48f7-bcf0-35d3ceeac243","session_ref":"/Users/jan/.claude/projects/-Users-jan-prg-CC-cc-backend/c31c699a-f492-48f7-bcf0-35d3ceeac243.jsonl"}
|
||||
{"time":"2026-03-11T05:43:59.204149+01:00","level":"INFO","msg":"turn-end","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"lifecycle","agent":"claude-code","event":"TurnEnd","session_id":"c31c699a-f492-48f7-bcf0-35d3ceeac243","session_ref":"/Users/jan/.claude/projects/-Users-jan-prg-CC-cc-backend/c31c699a-f492-48f7-bcf0-35d3ceeac243.jsonl"}
|
||||
{"time":"2026-03-11T05:43:59.565762+01:00","level":"INFO","msg":"committed changes to shadow branch","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"checkpoint","agent":"claude-code","shadow_branch":"entire/eba3995-e3b0c4"}
|
||||
{"time":"2026-03-11T05:43:59.565768+01:00","level":"INFO","msg":"checkpoint saved","session_id":"42401d2e-7d1c-4c0e-abe6-356cb2d48747","component":"checkpoint","agent":"claude-code","strategy":"manual-commit","checkpoint_type":"session","checkpoint_count":1,"modified_files":3,"new_files":3,"deleted_files":0,"shadow_branch":"entire/eba3995-e3b0c4","branch_created":false}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
There also have to be bugs in jobQuery.go . Especially the following query triggers the memory leak: SELECT * FROM job WHERE job.job_state IN ("completed", "running", "failed") ORDER BY job.start_time DESC LIMIT 1 OFFSET 10; Dig deeper to find the cause. Also investigate why no existing index is used for this query.
|
||||
What optimal index selection do you suggest? The job table contains almost 20 million jobs in production causing timouts on any filter query that does not use and index.
|
||||
@@ -1,27 +1,9 @@
|
||||
All passes. Here's a summary of findings and fixes:
|
||||
|
||||
---
|
||||
|
||||
## Findings
|
||||
The plan reduces 79 indexes to 20 by:
|
||||
|
||||
### Bug 1: Missing `defer rows.Close()` in `user.go:GetLdapUsernames()` (line 100)
|
||||
**Fixed.** Every call leaked a database connection and its buffers.
|
||||
- **Eliminating entire categories**: all `shared`-prefixed (16), all user/project sort variants (11), all standalone single-filter sorts (11)
|
||||
- **Consolidating**: cluster+jobstate sort variants replaced by `(cluster, sort_col)` which works for any state combo with LIMIT
|
||||
- **Keeping what matters**: the indexes SQLite actually picks with ANALYZE — `jobs_starttime`, `jobs_cluster_starttime_duration`, `jobs_user_starttime_duration`, `jobs_cluster_jobstate_duration_starttime`, and a few secondary sort indexes
|
||||
|
||||
### Bug 2: SQLite never runs `ANALYZE` — wrong index selection
|
||||
**Fixed.** Added `ANALYZE` to `setupSqlite()` in `dbConnection.go`.
|
||||
|
||||
Without statistics in `sqlite_stat1`, SQLite's query planner **guessed** and chose `jobs_jobstate_energy` (a terrible index for this query) instead of scanning `jobs_starttime` in reverse. The result:
|
||||
|
||||
| | Before ANALYZE | After ANALYZE |
|
||||
|---|---|---|
|
||||
| Index used | `jobs_jobstate_energy` | `jobs_starttime` |
|
||||
| Sort | **TEMP B-TREE** (materializes ALL rows) | None (index order) |
|
||||
| Memory | Proportional to total matching rows | Constant |
|
||||
| I/O | Full scan of all matching rows | Stops at OFFSET+LIMIT |
|
||||
|
||||
### Bug 3: `IN` clause + `ORDER BY` is fundamentally incompatible with composite indexes
|
||||
|
||||
Even with the "correct" index `(job_state, start_time)`, SQLite **cannot** merge-sort across 3 separate index range scans for `IN ('completed','running','failed')`. It always falls back to a temp B-tree sort. The only efficient plan is to use the standalone `jobs_starttime` index — which SQLite does automatically **after ANALYZE** because it realizes the 3 states cover virtually all rows, making the WHERE clause nearly a no-op.
|
||||
|
||||
### Observation: 79 indexes on the `job` table
|
||||
This is excessive and actively harmful — it confuses the query planner (especially without ANALYZE) and slows writes. The `jobs_jobstate_starttime` index from migration 08 is also missing from the actual DB (only the 3-column `jobs_jobstate_starttime_duration` exists). This is worth investigating separately but is a schema/migration concern, not a code bug.
|
||||
Key trade-off: ~20% of queries that sort by rare columns (num_hwthreads, num_acc, energy) with a state filter will now do a cheap per-row state check instead of using a 3-column composite. With LIMIT this is negligible.
|
||||
@@ -21,10 +21,11 @@ import (
|
||||
// is added to internal/repository/migrations/sqlite3/.
|
||||
//
|
||||
// Version history:
|
||||
// - Version 10: Current version
|
||||
// - Version 11: Optimize job table indexes (reduce from ~78 to 20)
|
||||
// - Version 10: Node table
|
||||
//
|
||||
// Migration files are embedded at build time from the migrations directory.
|
||||
const Version uint = 10
|
||||
const Version uint = 11
|
||||
|
||||
//go:embed migrations/*
|
||||
var migrationFiles embed.FS
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
-- Migration 11 DOWN: Restore all indexes from migration 09
|
||||
-- Reverts the index optimization by dropping the 20 optimized indexes
|
||||
-- and recreating the original full set.
|
||||
|
||||
-- ============================================================
|
||||
-- Drop optimized indexes
|
||||
-- ============================================================
|
||||
|
||||
DROP INDEX IF EXISTS jobs_starttime;
|
||||
DROP INDEX IF EXISTS jobs_cluster_starttime_duration;
|
||||
DROP INDEX IF EXISTS jobs_cluster_duration_starttime;
|
||||
DROP INDEX IF EXISTS jobs_cluster_jobstate_duration_starttime;
|
||||
DROP INDEX IF EXISTS jobs_cluster_jobstate_starttime_duration;
|
||||
DROP INDEX IF EXISTS jobs_cluster_user;
|
||||
DROP INDEX IF EXISTS jobs_cluster_project;
|
||||
DROP INDEX IF EXISTS jobs_cluster_subcluster;
|
||||
DROP INDEX IF EXISTS jobs_cluster_numnodes;
|
||||
DROP INDEX IF EXISTS jobs_user_starttime_duration;
|
||||
DROP INDEX IF EXISTS jobs_project_starttime_duration;
|
||||
DROP INDEX IF EXISTS jobs_jobstate_project;
|
||||
DROP INDEX IF EXISTS jobs_jobstate_user;
|
||||
DROP INDEX IF EXISTS jobs_jobstate_duration_starttime;
|
||||
DROP INDEX IF EXISTS jobs_arrayjobid;
|
||||
DROP INDEX IF EXISTS jobs_cluster_numhwthreads;
|
||||
DROP INDEX IF EXISTS jobs_cluster_numacc;
|
||||
DROP INDEX IF EXISTS jobs_cluster_energy;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_starttime;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_jobstate;
|
||||
|
||||
-- ============================================================
|
||||
-- Recreate all indexes from migration 09
|
||||
-- ============================================================
|
||||
|
||||
-- Cluster Filter
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_user ON job (cluster, hpc_user);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_project ON job (cluster, project);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_subcluster ON job (cluster, subcluster);
|
||||
-- Cluster Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_numnodes ON job (cluster, num_nodes);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_numhwthreads ON job (cluster, num_hwthreads);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_numacc ON job (cluster, num_acc);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_energy ON job (cluster, energy);
|
||||
|
||||
-- Cluster Time Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_duration_starttime ON job (cluster, duration, start_time);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_starttime_duration ON job (cluster, start_time, duration);
|
||||
|
||||
-- Cluster+Partition Filter
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_partition_user ON job (cluster, cluster_partition, hpc_user);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_partition_project ON job (cluster, cluster_partition, project);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_partition_jobstate ON job (cluster, cluster_partition, job_state);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_partition_shared ON job (cluster, cluster_partition, shared);
|
||||
|
||||
-- Cluster+Partition Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_partition_numnodes ON job (cluster, cluster_partition, num_nodes);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_partition_numhwthreads ON job (cluster, cluster_partition, num_hwthreads);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_partition_numacc ON job (cluster, cluster_partition, num_acc);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_partition_energy ON job (cluster, cluster_partition, energy);
|
||||
|
||||
-- Cluster+Partition Time Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_partition_duration_starttime ON job (cluster, cluster_partition, duration, start_time);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_partition_starttime_duration ON job (cluster, cluster_partition, start_time, duration);
|
||||
|
||||
-- Cluster+JobState Filter
|
||||
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);
|
||||
-- Cluster+JobState Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_numnodes ON job (cluster, job_state, num_nodes);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_numhwthreads ON job (cluster, job_state, num_hwthreads);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_numacc ON job (cluster, job_state, num_acc);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_energy ON job (cluster, job_state, energy);
|
||||
|
||||
-- Cluster+JobState Time Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_starttime_duration ON job (cluster, job_state, start_time, duration);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_jobstate_duration_starttime ON job (cluster, job_state, duration, start_time);
|
||||
|
||||
-- Cluster+Shared Filter
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_shared_user ON job (cluster, shared, hpc_user);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_shared_project ON job (cluster, shared, project);
|
||||
-- Cluster+Shared Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_shared_numnodes ON job (cluster, shared, num_nodes);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_shared_numhwthreads ON job (cluster, shared, num_hwthreads);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_shared_numacc ON job (cluster, shared, num_acc);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_shared_energy ON job (cluster, shared, energy);
|
||||
|
||||
-- Cluster+Shared Time Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_shared_starttime_duration ON job (cluster, shared, start_time, duration);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_shared_duration_starttime ON job (cluster, shared, duration, start_time);
|
||||
|
||||
-- User Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_user_numnodes ON job (hpc_user, num_nodes);
|
||||
CREATE INDEX IF NOT EXISTS jobs_user_numhwthreads ON job (hpc_user, num_hwthreads);
|
||||
CREATE INDEX IF NOT EXISTS jobs_user_numacc ON job (hpc_user, num_acc);
|
||||
CREATE INDEX IF NOT EXISTS jobs_user_energy ON job (hpc_user, energy);
|
||||
|
||||
-- User Time Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_user_starttime_duration ON job (hpc_user, start_time, duration);
|
||||
CREATE INDEX IF NOT EXISTS jobs_user_duration_starttime ON job (hpc_user, duration, start_time);
|
||||
|
||||
-- Project Filter
|
||||
CREATE INDEX IF NOT EXISTS jobs_project_user ON job (project, hpc_user);
|
||||
-- Project Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_project_numnodes ON job (project, num_nodes);
|
||||
CREATE INDEX IF NOT EXISTS jobs_project_numhwthreads ON job (project, num_hwthreads);
|
||||
CREATE INDEX IF NOT EXISTS jobs_project_numacc ON job (project, num_acc);
|
||||
CREATE INDEX IF NOT EXISTS jobs_project_energy ON job (project, energy);
|
||||
|
||||
-- Project Time Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_project_starttime_duration ON job (project, start_time, duration);
|
||||
CREATE INDEX IF NOT EXISTS jobs_project_duration_starttime ON job (project, duration, start_time);
|
||||
|
||||
-- JobState Filter
|
||||
CREATE INDEX IF NOT EXISTS jobs_jobstate_user ON job (job_state, hpc_user);
|
||||
CREATE INDEX IF NOT EXISTS jobs_jobstate_project ON job (job_state, project);
|
||||
-- JobState Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_jobstate_numnodes ON job (job_state, num_nodes);
|
||||
CREATE INDEX IF NOT EXISTS jobs_jobstate_numhwthreads ON job (job_state, num_hwthreads);
|
||||
CREATE INDEX IF NOT EXISTS jobs_jobstate_numacc ON job (job_state, num_acc);
|
||||
CREATE INDEX IF NOT EXISTS jobs_jobstate_energy ON job (job_state, energy);
|
||||
|
||||
-- JobState Time Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_jobstate_starttime_duration ON job (job_state, start_time, duration);
|
||||
CREATE INDEX IF NOT EXISTS jobs_jobstate_duration_starttime ON job (job_state, duration, start_time);
|
||||
|
||||
-- Shared Filter
|
||||
CREATE INDEX IF NOT EXISTS jobs_shared_user ON job (shared, hpc_user);
|
||||
CREATE INDEX IF NOT EXISTS jobs_shared_project ON job (shared, project);
|
||||
-- Shared Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_shared_numnodes ON job (shared, num_nodes);
|
||||
CREATE INDEX IF NOT EXISTS jobs_shared_numhwthreads ON job (shared, num_hwthreads);
|
||||
CREATE INDEX IF NOT EXISTS jobs_shared_numacc ON job (shared, num_acc);
|
||||
CREATE INDEX IF NOT EXISTS jobs_shared_energy ON job (shared, energy);
|
||||
|
||||
-- Shared Time Filter Sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_shared_starttime_duration ON job (shared, start_time, duration);
|
||||
CREATE INDEX IF NOT EXISTS jobs_shared_duration_starttime ON job (shared, duration, start_time);
|
||||
|
||||
-- ArrayJob Filter
|
||||
CREATE INDEX IF NOT EXISTS jobs_arrayjobid_starttime ON job (array_job_id, start_time);
|
||||
CREATE INDEX IF NOT EXISTS jobs_cluster_arrayjobid_starttime ON job (cluster, array_job_id, start_time);
|
||||
|
||||
-- Single filters with default starttime sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_duration_starttime ON job (duration, start_time);
|
||||
CREATE INDEX IF NOT EXISTS jobs_numnodes_starttime ON job (num_nodes, start_time);
|
||||
CREATE INDEX IF NOT EXISTS jobs_numhwthreads_starttime ON job (num_hwthreads, start_time);
|
||||
CREATE INDEX IF NOT EXISTS jobs_numacc_starttime ON job (num_acc, start_time);
|
||||
CREATE INDEX IF NOT EXISTS jobs_energy_starttime ON job (energy, start_time);
|
||||
|
||||
-- Single filters with duration sorting
|
||||
CREATE INDEX IF NOT EXISTS jobs_starttime_duration ON job (start_time, duration);
|
||||
CREATE INDEX IF NOT EXISTS jobs_numnodes_duration ON job (num_nodes, duration);
|
||||
CREATE INDEX IF NOT EXISTS jobs_numhwthreads_duration ON job (num_hwthreads, duration);
|
||||
CREATE INDEX IF NOT EXISTS jobs_numacc_duration ON job (num_acc, duration);
|
||||
CREATE INDEX IF NOT EXISTS jobs_energy_duration ON job (energy, duration);
|
||||
|
||||
-- Backup Indices For High Variety Columns
|
||||
CREATE INDEX IF NOT EXISTS jobs_starttime ON job (start_time);
|
||||
CREATE INDEX IF NOT EXISTS jobs_duration ON job (duration);
|
||||
|
||||
-- Optimize DB index usage
|
||||
PRAGMA optimize;
|
||||
@@ -0,0 +1,221 @@
|
||||
-- Migration 11: Optimize job table indexes
|
||||
-- Reduces from ~78 indexes to 20 for better write performance,
|
||||
-- reduced disk usage, and more reliable query planner decisions.
|
||||
-- Requires ANALYZE to be run after migration (done automatically on startup).
|
||||
|
||||
-- ============================================================
|
||||
-- Drop ALL existing job indexes (from migrations 08/09)
|
||||
-- sqlite_autoindex_job_1 (UNIQUE constraint) is kept automatically
|
||||
-- ============================================================
|
||||
|
||||
-- Cluster Filter
|
||||
DROP INDEX IF EXISTS jobs_cluster_user;
|
||||
DROP INDEX IF EXISTS jobs_cluster_project;
|
||||
DROP INDEX IF EXISTS jobs_cluster_subcluster;
|
||||
-- Cluster Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_cluster_numnodes;
|
||||
DROP INDEX IF EXISTS jobs_cluster_numhwthreads;
|
||||
DROP INDEX IF EXISTS jobs_cluster_numacc;
|
||||
DROP INDEX IF EXISTS jobs_cluster_energy;
|
||||
-- Cluster Time Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_cluster_duration_starttime;
|
||||
DROP INDEX IF EXISTS jobs_cluster_starttime_duration;
|
||||
|
||||
-- Cluster+Partition Filter
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_user;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_project;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_jobstate;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_shared;
|
||||
-- Cluster+Partition Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_numnodes;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_numhwthreads;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_numacc;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_energy;
|
||||
-- Cluster+Partition Time Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_duration_starttime;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_starttime_duration;
|
||||
|
||||
-- Cluster+JobState Filter
|
||||
DROP INDEX IF EXISTS jobs_cluster_jobstate_user;
|
||||
DROP INDEX IF EXISTS jobs_cluster_jobstate_project;
|
||||
-- Cluster+JobState Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_cluster_jobstate_numnodes;
|
||||
DROP INDEX IF EXISTS jobs_cluster_jobstate_numhwthreads;
|
||||
DROP INDEX IF EXISTS jobs_cluster_jobstate_numacc;
|
||||
DROP INDEX IF EXISTS jobs_cluster_jobstate_energy;
|
||||
-- Cluster+JobState Time Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_cluster_jobstate_starttime_duration;
|
||||
DROP INDEX IF EXISTS jobs_cluster_jobstate_duration_starttime;
|
||||
|
||||
-- Cluster+Shared Filter
|
||||
DROP INDEX IF EXISTS jobs_cluster_shared_user;
|
||||
DROP INDEX IF EXISTS jobs_cluster_shared_project;
|
||||
-- Cluster+Shared Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_cluster_shared_numnodes;
|
||||
DROP INDEX IF EXISTS jobs_cluster_shared_numhwthreads;
|
||||
DROP INDEX IF EXISTS jobs_cluster_shared_numacc;
|
||||
DROP INDEX IF EXISTS jobs_cluster_shared_energy;
|
||||
-- Cluster+Shared Time Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_cluster_shared_starttime_duration;
|
||||
DROP INDEX IF EXISTS jobs_cluster_shared_duration_starttime;
|
||||
|
||||
-- User Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_user_numnodes;
|
||||
DROP INDEX IF EXISTS jobs_user_numhwthreads;
|
||||
DROP INDEX IF EXISTS jobs_user_numacc;
|
||||
DROP INDEX IF EXISTS jobs_user_energy;
|
||||
-- User Time Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_user_starttime_duration;
|
||||
DROP INDEX IF EXISTS jobs_user_duration_starttime;
|
||||
|
||||
-- Project Filter
|
||||
DROP INDEX IF EXISTS jobs_project_user;
|
||||
-- Project Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_project_numnodes;
|
||||
DROP INDEX IF EXISTS jobs_project_numhwthreads;
|
||||
DROP INDEX IF EXISTS jobs_project_numacc;
|
||||
DROP INDEX IF EXISTS jobs_project_energy;
|
||||
-- Project Time Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_project_starttime_duration;
|
||||
DROP INDEX IF EXISTS jobs_project_duration_starttime;
|
||||
|
||||
-- JobState Filter
|
||||
DROP INDEX IF EXISTS jobs_jobstate_user;
|
||||
DROP INDEX IF EXISTS jobs_jobstate_project;
|
||||
-- JobState Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_jobstate_numnodes;
|
||||
DROP INDEX IF EXISTS jobs_jobstate_numhwthreads;
|
||||
DROP INDEX IF EXISTS jobs_jobstate_numacc;
|
||||
DROP INDEX IF EXISTS jobs_jobstate_energy;
|
||||
-- JobState Time Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_jobstate_starttime_duration;
|
||||
DROP INDEX IF EXISTS jobs_jobstate_duration_starttime;
|
||||
|
||||
-- Shared Filter
|
||||
DROP INDEX IF EXISTS jobs_shared_user;
|
||||
DROP INDEX IF EXISTS jobs_shared_project;
|
||||
-- Shared Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_shared_numnodes;
|
||||
DROP INDEX IF EXISTS jobs_shared_numhwthreads;
|
||||
DROP INDEX IF EXISTS jobs_shared_numacc;
|
||||
DROP INDEX IF EXISTS jobs_shared_energy;
|
||||
-- Shared Time Filter Sorting
|
||||
DROP INDEX IF EXISTS jobs_shared_starttime_duration;
|
||||
DROP INDEX IF EXISTS jobs_shared_duration_starttime;
|
||||
|
||||
-- ArrayJob Filter
|
||||
DROP INDEX IF EXISTS jobs_arrayjobid_starttime;
|
||||
DROP INDEX IF EXISTS jobs_cluster_arrayjobid_starttime;
|
||||
|
||||
-- Single filters with default starttime sorting
|
||||
DROP INDEX IF EXISTS jobs_duration_starttime;
|
||||
DROP INDEX IF EXISTS jobs_numnodes_starttime;
|
||||
DROP INDEX IF EXISTS jobs_numhwthreads_starttime;
|
||||
DROP INDEX IF EXISTS jobs_numacc_starttime;
|
||||
DROP INDEX IF EXISTS jobs_energy_starttime;
|
||||
|
||||
-- Single filters with duration sorting
|
||||
DROP INDEX IF EXISTS jobs_starttime_duration;
|
||||
DROP INDEX IF EXISTS jobs_numnodes_duration;
|
||||
DROP INDEX IF EXISTS jobs_numhwthreads_duration;
|
||||
DROP INDEX IF EXISTS jobs_numacc_duration;
|
||||
DROP INDEX IF EXISTS jobs_energy_duration;
|
||||
|
||||
-- Backup Indices
|
||||
DROP INDEX IF EXISTS jobs_starttime;
|
||||
DROP INDEX IF EXISTS jobs_duration;
|
||||
|
||||
-- Legacy indexes from migration 08 (may exist on older DBs)
|
||||
DROP INDEX IF EXISTS jobs_cluster;
|
||||
DROP INDEX IF EXISTS jobs_cluster_starttime;
|
||||
DROP INDEX IF EXISTS jobs_cluster_duration;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_starttime;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_duration;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_numnodes;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_numhwthreads;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_numacc;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_energy;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_jobstate_user;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_jobstate_project;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_jobstate_starttime;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_jobstate_duration;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_jobstate_numnodes;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_jobstate_numhwthreads;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_jobstate_numacc;
|
||||
DROP INDEX IF EXISTS jobs_cluster_partition_jobstate_energy;
|
||||
DROP INDEX IF EXISTS jobs_cluster_jobstate;
|
||||
DROP INDEX IF EXISTS jobs_cluster_jobstate_starttime;
|
||||
DROP INDEX IF EXISTS jobs_cluster_jobstate_duration;
|
||||
DROP INDEX IF EXISTS jobs_user;
|
||||
DROP INDEX IF EXISTS jobs_user_starttime;
|
||||
DROP INDEX IF EXISTS jobs_user_duration;
|
||||
DROP INDEX IF EXISTS jobs_project;
|
||||
DROP INDEX IF EXISTS jobs_project_starttime;
|
||||
DROP INDEX IF EXISTS jobs_project_duration;
|
||||
DROP INDEX IF EXISTS jobs_jobstate;
|
||||
DROP INDEX IF EXISTS jobs_jobstate_cluster;
|
||||
DROP INDEX IF EXISTS jobs_jobstate_starttime;
|
||||
DROP INDEX IF EXISTS jobs_jobstate_duration;
|
||||
DROP INDEX IF EXISTS jobs_numnodes;
|
||||
DROP INDEX IF EXISTS jobs_numhwthreads;
|
||||
DROP INDEX IF EXISTS jobs_numacc;
|
||||
DROP INDEX IF EXISTS jobs_energy;
|
||||
|
||||
-- ============================================================
|
||||
-- Create optimized set of 20 indexes
|
||||
-- ============================================================
|
||||
|
||||
-- GROUP 1: Global sort (1 index)
|
||||
-- Default sort for unfiltered/multi-state IN queries, time range, delete-before
|
||||
CREATE INDEX jobs_starttime ON job (start_time);
|
||||
|
||||
-- GROUP 2: Cluster-prefixed (8 indexes)
|
||||
-- Cluster + default sort, concurrent jobs, time range within cluster
|
||||
CREATE INDEX jobs_cluster_starttime_duration ON job (cluster, start_time, duration);
|
||||
-- Cluster + sort by duration
|
||||
CREATE INDEX jobs_cluster_duration_starttime ON job (cluster, duration, start_time);
|
||||
-- COVERING for cluster+state aggregation; running jobs (cluster, state, duration>?)
|
||||
CREATE INDEX jobs_cluster_jobstate_duration_starttime ON job (cluster, job_state, duration, start_time);
|
||||
-- Cluster+state+sort start_time (single state equality)
|
||||
CREATE INDEX jobs_cluster_jobstate_starttime_duration ON job (cluster, job_state, start_time, duration);
|
||||
-- COVERING for GROUP BY user with cluster filter
|
||||
CREATE INDEX jobs_cluster_user ON job (cluster, hpc_user);
|
||||
-- GROUP BY project with cluster filter
|
||||
CREATE INDEX jobs_cluster_project ON job (cluster, project);
|
||||
-- GROUP BY subcluster with cluster filter
|
||||
CREATE INDEX jobs_cluster_subcluster ON job (cluster, subcluster);
|
||||
-- Cluster + sort by num_nodes (state filtered per-row, fast with LIMIT)
|
||||
CREATE INDEX jobs_cluster_numnodes ON job (cluster, num_nodes);
|
||||
|
||||
-- GROUP 3: User-prefixed (1 index)
|
||||
-- Security filter (user role) + default sort
|
||||
CREATE INDEX jobs_user_starttime_duration ON job (hpc_user, start_time, duration);
|
||||
|
||||
-- GROUP 4: Project-prefixed (1 index)
|
||||
-- Security filter (manager role) + default sort
|
||||
CREATE INDEX jobs_project_starttime_duration ON job (project, start_time, duration);
|
||||
|
||||
-- GROUP 5: JobState-prefixed (3 indexes)
|
||||
-- State + project filter (for manager security within state query)
|
||||
CREATE INDEX jobs_jobstate_project ON job (job_state, project);
|
||||
-- State + user filter/aggregation
|
||||
CREATE INDEX jobs_jobstate_user ON job (job_state, hpc_user);
|
||||
-- COVERING for non-running jobs scan, state + sort duration
|
||||
CREATE INDEX jobs_jobstate_duration_starttime ON job (job_state, duration, start_time);
|
||||
|
||||
-- GROUP 6: Rare filters (1 index)
|
||||
-- Array job lookup
|
||||
CREATE INDEX jobs_arrayjobid ON job (array_job_id);
|
||||
|
||||
-- GROUP 7: Secondary sort columns (5 indexes)
|
||||
CREATE INDEX jobs_cluster_numhwthreads ON job (cluster, num_hwthreads);
|
||||
CREATE INDEX jobs_cluster_numacc ON job (cluster, num_acc);
|
||||
CREATE INDEX jobs_cluster_energy ON job (cluster, energy);
|
||||
-- Cluster+partition + sort start_time
|
||||
CREATE INDEX jobs_cluster_partition_starttime ON job (cluster, cluster_partition, start_time);
|
||||
-- Cluster+partition+state filter
|
||||
CREATE INDEX jobs_cluster_partition_jobstate ON job (cluster, cluster_partition, job_state);
|
||||
|
||||
-- Optimize DB index usage
|
||||
PRAGMA optimize;
|
||||
Reference in New Issue
Block a user