Commit f6efa56
Andrew Cheng
Optimize q filter to use pk__in subqueries instead of set operations
The `q` complex filter composed its NOT/AND/OR operands with QuerySet
.difference()/.intersection()/.union(), which compile to SQL
EXCEPT/INTERSECT/UNION. For NOT in particular, the left operand is the
full unfiltered queryset, so evaluating an expression like
`repository_version=X AND NOT repository_version=Y` seq-scans the entire
content table and sorts/hashes every leg, spilling to disk on large
repositories.
Rewrite the three operand evaluators to compose with `pk__in` subqueries:
- _NotAction: qs.exclude(pk__in=expr.evaluate(qs).values("pk"))
- _AndAction: chained qs.filter(pk__in=...) semi-joins
- _OrAction: OR of Q(pk__in=...) subqueries
This collapses the plan to indexed anti-/semi-joins with no full-table
scan, no SetOp, and no disk-spilling sorts. Results are unchanged (each
operand still filters the same base queryset on a unique pk, so the
implicit de-duplication of the set operations is preserved); the
existing q filter functional tests pass without modification.
Benchmarked on a 200k-unit repository computing a 1000-unit diff
between two repository versions (steady-state, work_mem=4MB):
Version sizes Before (set-ops) After (pk__in)
--------------- ------------------ ----------------
199k units ~1400 ms ~680 ms
50k units ~450 ms ~150 ms
Planning time also drops (e.g. ~1.4 ms -> ~0.5 ms) as the large inlined
operand lists are replaced by parameterized subqueries.
Closes #7831
Assisted by: Claude Opus 4.81 parent 0979b88 commit f6efa56
2 files changed
Lines changed: 12 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
215 | 215 | | |
216 | 216 | | |
217 | 217 | | |
218 | | - | |
| 218 | + | |
219 | 219 | | |
220 | 220 | | |
221 | 221 | | |
222 | 222 | | |
223 | 223 | | |
224 | 224 | | |
225 | 225 | | |
226 | | - | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
231 | 230 | | |
232 | 231 | | |
233 | 232 | | |
234 | 233 | | |
235 | 234 | | |
236 | 235 | | |
237 | 236 | | |
238 | | - | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
239 | 241 | | |
240 | 242 | | |
241 | 243 | | |
| |||
0 commit comments