Skip to content

perf: eliminate N+1 in IssueSerializer and dedupe cycle conflict check#4

Draft
d0cd wants to merge 1 commit into
previewfrom
d0cd/fix-performance-issues-716m28
Draft

perf: eliminate N+1 in IssueSerializer and dedupe cycle conflict check#4
d0cd wants to merge 1 commit into
previewfrom
d0cd/fix-performance-issues-716m28

Conversation

@d0cd
Copy link
Copy Markdown

@d0cd d0cd commented Apr 28, 2026

Summary

  • IssueSerializer.to_representation (apps/api/plane/api/serializers/issue.py): replaced four fresh IssueAssignee.objects.filter(issue=instance) / IssueLabel.objects.filter(issue=instance) queries with reads against the M2M prefetch cache that the view already populates via prefetch_related(\"assignees\", \"labels\"). Listing N issues went from O(N) extra DB round-trips per relation to zero.
  • CycleListCreateAPIEndpoint.post (apps/api/plane/api/views/cycle.py): the external-id conflict check ran the same Cycle.objects.filter(...) twice (once as .exists(), once as .first()). Collapsed into a single .first() lookup.

These are two of the highest-impact, lowest-risk wins surfaced by an audit of the public REST API hot paths.

Test plan

  • GET /api/v1/workspaces/<slug>/projects/<pid>/issues/ returns the same payload (assignees + labels arrays of UUID strings)
  • Same endpoint with ?expand=assignees,labels still returns expanded user/label objects
  • Confirm via django-debug-toolbar (or Django ORM logging) that issue list endpoints no longer fan out per-issue assignee/label queries
  • POST /api/v1/.../cycles/ with a duplicate external_id/external_source pair still returns 409 with the existing cycle id

🤖 Generated with Claude Code
🌒 Run on Niteshift: View Task

…ict check

- IssueSerializer.to_representation now reads assignees/labels from the
  existing prefetched M2M cache instead of issuing fresh IssueAssignee /
  IssueLabel filter queries per instance. The view's get_queryset already
  prefetches both relations, so every issue serialized in a list endpoint
  was wasting up to 4 extra queries.

- CycleListCreate.post collapses the duplicate "exists check then refetch"
  pair into a single .first() lookup.

Run-on: Niteshift Staging

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant