correlated EXISTS is ~128.69× slower than IN (subquery)
A correlated `EXISTS` is not rewritten into a join by SQLite: it becomes 100,000 primary-key lookups (129× slower). The `IN (subquery)` form scans once.
Result
| Run | correlated EXISTS | IN (subquery) | Ratio |
|---|---|---|---|
| Run 1 | 805.394 | 6.037 | 133.41× |
| Run 2 | 827.471 | 6.535 | 126.61× |
| Run 3 | 830.536 | 6.454 | 128.69× |
Spread over 3 runs: correlated EXISTS CV 1.4% / IN (subquery) CV 3.4% / Ratio CV 2.2%
The statement
SELECT id FROM items i WHERE EXISTS (SELECT 1 FROM items x WHERE x.id=i.id AND x.score>900) LIMIT 400; SELECT id FROM items WHERE id IN (SELECT id FROM items WHERE score>900) LIMIT 400; Conditions
100,000 rows; `id` is the primary key and `score` is indexed.
Where this number does not apply
If the correlated table is small, or the outer query returns few rows, the gap shrinks.
Reproduce
cd bench && python sqbench.py --samples 9 --out ../data/run.json