Commit 934e79d
/crawlstats: stop paying thirty seconds for a planner's guess (#143)
Three findings, measured against production at 444,009 feeds.
**This database has never been ANALYZEd.** There is no `sqlite_stat1`, so SQLite
falls back to its built-in guess that an equality test is more selective than a
range test. Two of `jobBacklogs`'s five reads ask for a date and filter on a
status, and the guess picks the status index for both:
submitted 17,722ms -> 654ms (seeks 330k `pending` rows to find 5,954)
enriched 16,067ms -> 119ms (seeks 109k `active` rows; the partial index
is keyed by the very column being counted)
Both are now `indexed by`. Identical results, 27x and 135x. Not a hint SQLite
may ignore -- naming a missing index fails at prepare time -- so a test asserts
both indexes exist as well as asserting the plans.
**The API route bypassed every cache the page uses.** `/api/crawlstats` called
`q.jobBacklogs` directly while `/crawlstats` has always called the cached
reader, which is why the endpoint took 53 seconds to serve numbers the page
rendered in 3.7. It now uses the same reader. The liveness numbers stay
uncached -- `crawlStats` and `logActivity` are still read fresh -- so the
endpoint still cannot report a dead crawler as alive, which is the one thing a
status endpoint must never do.
Together: jobBacklogs 27.9s -> 3.2s cold and 263ms warm, and the JSON endpoint
drops from 53s to roughly the page's own cost.
Left alone deliberately. `categoryStats`'s totals query wants `status`,
`last_success_at` and `item_count` for every non-dead row and cannot finish
inside the 30s deadline; the covering index that would fix it is over three
columns rewritten on every crawl, and writes are the binding constraint. It is
served stale-while-revalidate and the stale value is what the page shows.
`failingFeeds` (2.4s) sorts every error row by `error_count`, which is written
on every successful crawl too, so an index there has the same problem. Both want
a rollup rather than an index.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>1 parent 2087c34 commit 934e79d
3 files changed
Lines changed: 136 additions & 5 deletions
File tree
- apps/web/src/app/api/crawlstats
- packages/db
- src
- test
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
47 | 57 | | |
48 | 58 | | |
49 | 59 | | |
| |||
52 | 62 | | |
53 | 63 | | |
54 | 64 | | |
55 | | - | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
56 | 70 | | |
57 | 71 | | |
58 | 72 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1398 | 1398 | | |
1399 | 1399 | | |
1400 | 1400 | | |
| 1401 | + | |
| 1402 | + | |
| 1403 | + | |
| 1404 | + | |
| 1405 | + | |
| 1406 | + | |
| 1407 | + | |
| 1408 | + | |
1401 | 1409 | | |
1402 | | - | |
| 1410 | + | |
| 1411 | + | |
1403 | 1412 | | |
1404 | 1413 | | |
1405 | 1414 | | |
| |||
1417 | 1426 | | |
1418 | 1427 | | |
1419 | 1428 | | |
| 1429 | + | |
| 1430 | + | |
| 1431 | + | |
| 1432 | + | |
| 1433 | + | |
| 1434 | + | |
1420 | 1435 | | |
1421 | 1436 | | |
1422 | 1437 | | |
1423 | | - | |
| 1438 | + | |
1424 | 1439 | | |
1425 | 1440 | | |
1426 | 1441 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
0 commit comments