perf(db): drop redundant idx_edges_source / idx_edges_target (#142)

Both narrow indexes are fully covered by the existing (source, kind)
and (target, kind) composites via SQLite's left-prefix scan, so
they're dead weight on every write. Empirical measurements (from the
spike script in PR #122 on a 50K-node / 250K-edge synthetic DB):

  - DB size: 34.7 MB → 27.0 MB (-22.2%)
  - Bulk insert (250K edges): 590ms → 431ms (1.37× faster)
  - source/target lookup latency: no regression

Adds migration v4 to drop both on existing databases; fresh-DB schema
no longer creates them.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-05-07 21:29:00 -05:00
committed by GitHub
co-authored by Claude Opus 4.7
parent 153fd1e974
commit a460b856c2
4 changed files with 20 additions and 6 deletions
+12 -1
View File
@@ -9,7 +9,7 @@ import { SqliteDatabase } from './sqlite-adapter';
/**
* Current schema version
*/
export const CURRENT_SCHEMA_VERSION = 3;
export const CURRENT_SCHEMA_VERSION = 4;
/**
* Migration definition
@@ -54,6 +54,17 @@ const migrations: Migration[] = [
`);
},
},
{
version: 4,
description:
'Drop redundant idx_edges_source / idx_edges_target (covered by source_kind / target_kind composites)',
up: (db) => {
db.exec(`
DROP INDEX IF EXISTS idx_edges_source;
DROP INDEX IF EXISTS idx_edges_target;
`);
},
},
];
/**
+6 -3
View File
@@ -122,9 +122,12 @@ CREATE TRIGGER IF NOT EXISTS nodes_au AFTER UPDATE ON nodes BEGIN
VALUES (NEW.rowid, NEW.id, NEW.name, NEW.qualified_name, NEW.docstring, NEW.signature);
END;
-- Edge indexes
CREATE INDEX IF NOT EXISTS idx_edges_source ON edges(source);
CREATE INDEX IF NOT EXISTS idx_edges_target ON edges(target);
-- Edge indexes.
-- idx_edges_source / idx_edges_target are intentionally omitted —
-- the (source, kind) and (target, kind) composites below cover the
-- corresponding source-only / target-only lookups via SQLite's
-- left-prefix scan, so the narrow indexes are dead weight on writes.
-- Migration v4 drops them on existing databases.
CREATE INDEX IF NOT EXISTS idx_edges_kind ON edges(kind);
CREATE INDEX IF NOT EXISTS idx_edges_source_kind ON edges(source, kind);
CREATE INDEX IF NOT EXISTS idx_edges_target_kind ON edges(target, kind);