Applications and companies tables: an unconditional DISTINCT makes every count and page de-duplicate whole rows #552
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#552
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-09-29 in a read-only review of postulo at
95348908d, by reading the tables' querysets, capturing their SQL and timing them with and withoutDISTINCT.Checked again on 2026-10-01 against
mainat0a5cad587: still present.ApplicationFilterMixin.filter_querysetandCompanyListView.get_querysetboth end in.distinct()whatever was asked. The paginator's count then becomesCOUNT(*)over aSELECT DISTINCTof every selected column and every correlated subquery, and the page query de-duplicates whole rows, the posting's description included, so neither can stop at the page's rows. On the applications table no filter can repeat a row, so theDISTINCTbuys nothing; on the companies table only two filters need it.applications/views.py:113(return queryset.distinct()inApplicationFilterMixin.filter_queryset, shared by the table and the board)jobs/views.py:105(return self.table.apply(queryset).distinct()inCompanyListView.get_queryset)postingandposting__company(single foreign keys),status,priority,channeland dates are columns, the quiet and state filters use annotations, andtags__slugmatches at most one tag per application because slugs are unique per owner (unique_tag_slug_per_owner). On companies, onlyq(throughindustries__nameandidentifiers__value) and the Industries column filter (jobs/tables.py:53-57) join a many-valued relation. With 1,500 applications and 800 companies on SQLite:DISTINCT, 3 ms without; page of 50: 57 ms against 29 ms.distinct()fromApplicationFilterMixin.filter_queryset. On companies, express the search's industry and identifier matches asExists(...), ascore/search.py:251-252already does, and apply.distinct()only when the Industries column filter is present (or give that column anExistslookup too), so the plain table never needs it.Related to #231 (closed), whose item 2 named "search joins and
.distinct()on top" and replaced the aggregates with subqueries but left the unconditionalDISTINCT.Done when
tests/test_tables.pycaptures the SQL of the applications table and the companies table with no filters and asserts neither containsDISTINCT; a second asserts a company in two matching industries still appears once when filtered by industry.Landed on main with a green Forgejo CI run. Its entry in the CHANGELOG's Unreleased section ends in (#552).