mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-25 20:12:11 +08:00
fix(explore): pin the dominant-file aggregation to an edges-first plan (#2575)
The dominant-file aggregation behind codegraph_explore could let SQLite drive the query from the nodes table, which on a large index took seconds to a minute. The query now pins an edges-first plan. On four indexes it returns the same rows, 4 to 12 times faster. Fixes issue 2571. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b5553e238a
commit
c8f154b9f4
+24
-10
@@ -242,6 +242,28 @@ function rowToFileRecord(row: FileRow): FileRecord {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Files ranked by edges between two of their own symbols — the input to
|
||||
* `getDominantFile`. CROSS JOIN pins the loop order to edges first, then a
|
||||
* lookup by id for each end: one pass over the edges whatever the statistics
|
||||
* say. With a plain JOIN the planner may start from nodes and, for each node,
|
||||
* walk every node in its file and probe edges by (source, target) — quadratic
|
||||
* in nodes per file. Sampled stats (`analysis_limit` + `PRAGMA optimize`) can
|
||||
* under-count nodes per file and pick that plan, and a few huge files (a
|
||||
* generated R.java) then cost ~100 s (#2571). Ties go to the path, so the
|
||||
* plan never decides between equal counts.
|
||||
*/
|
||||
export const DOMINANT_FILE_SQL = `
|
||||
SELECT n.file_path AS file_path, COUNT(*) AS edge_count
|
||||
FROM edges e
|
||||
CROSS JOIN nodes n ON e.source = n.id
|
||||
CROSS JOIN nodes m ON e.target = m.id
|
||||
WHERE n.file_path = m.file_path
|
||||
GROUP BY n.file_path
|
||||
ORDER BY edge_count DESC, n.file_path
|
||||
LIMIT 20
|
||||
`;
|
||||
|
||||
/**
|
||||
* Query builder for the knowledge graph database
|
||||
*/
|
||||
@@ -1169,16 +1191,8 @@ export class QueryBuilder {
|
||||
// protobuf stub) outranks the real `server/etcdserver/server.go`
|
||||
// (470 edges) by 4×, and the boost would push the agent toward
|
||||
// generated code.
|
||||
this.stmts.getDominantFile = this.db.prepare(`
|
||||
SELECT n.file_path AS file_path, COUNT(*) AS edge_count
|
||||
FROM edges e
|
||||
JOIN nodes n ON e.source = n.id
|
||||
JOIN nodes m ON e.target = m.id
|
||||
WHERE n.file_path = m.file_path
|
||||
GROUP BY n.file_path
|
||||
ORDER BY edge_count DESC
|
||||
LIMIT 20
|
||||
`);
|
||||
// Edges-first and tie-broken by path on purpose: see DOMINANT_FILE_SQL (#2571).
|
||||
this.stmts.getDominantFile = this.db.prepare(DOMINANT_FILE_SQL);
|
||||
}
|
||||
const rows = this.stmts.getDominantFile.all() as Array<{ file_path: string; edge_count: number }>;
|
||||
const generated = this.getGeneratedPathsAmong(rows.map(r => r.file_path));
|
||||
|
||||
Reference in New Issue
Block a user