Skip to content

Commit 9bfdb60

Browse files
committed
Optimize subtree delete lookup
Replace the subtree LIKE predicate with exact-root and bounded child range deletes so SQLite can use the (scan_id, path) primary key instead of scanning every row in the scan. Benchmarks on the real 7.07M-entry / cache showed old LIKE predicates taking ~17-23s regardless of subtree size, while the new range predicate scaled with subtree size: /Applications ~18.0s -> ~0.85s, /System ~17.7s -> ~0.73s, /Library ~20.7s -> ~0.27s, /opt ~21.4s -> ~0.07s, /private ~18.9s -> ~0.02s, /bin ~22.2s -> ~0.02s. /Users, which covers most of the scan, improved ~20.8s -> ~16.0s. A synthetic actual DELETE benchmark with 1,001,001 rows deleting a 1,001-row subtree improved from ~114ms to ~19ms.
1 parent 86f71f7 commit 9bfdb60

1 file changed

Lines changed: 20 additions & 4 deletions

File tree

disk_analyzer_cli/lib/src/storage/database.dart

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -307,10 +307,26 @@ class DiskDatabase {
307307
/// Delete all entries under a subtree path within a scan (inclusive).
308308
/// Uses exact path match + path prefix with '/' boundary to avoid prefix collisions.
309309
void deleteSubtree(int scanId, String subtreePath) {
310-
_db.execute(
311-
'DELETE FROM entries WHERE scan_id = ? AND (path = ? OR path LIKE ? || \'/%\')',
312-
[scanId, subtreePath, subtreePath],
313-
);
310+
final childPrefix = subtreePath == '/' ? '/' : '$subtreePath/';
311+
// '/' sorts immediately before '0', giving a tight upper bound for children.
312+
final childUpperBound = subtreePath == '/' ? '0' : '${subtreePath}0';
313+
314+
_db.execute('BEGIN TRANSACTION');
315+
try {
316+
_db.execute('DELETE FROM entries WHERE scan_id = ? AND path = ?', [
317+
scanId,
318+
subtreePath,
319+
]);
320+
_db.execute(
321+
'DELETE FROM entries '
322+
'WHERE scan_id = ? AND path >= ? AND path < ?',
323+
[scanId, childPrefix, childUpperBound],
324+
);
325+
_db.execute('COMMIT');
326+
} catch (e) {
327+
_db.execute('ROLLBACK');
328+
rethrow;
329+
}
314330
}
315331

316332
/// Get the depth of an entry in a scan.

0 commit comments

Comments
 (0)