Skip to content

Fix full-catalog homepage performance - #763

Merged
jochengcd merged 5 commits into
GrandComicsDatabase:betafrom
ProfNardi:fix/catalog-homepage-series-search
Sep 25, 2026
Merged

jochengcd merged 5 commits into
GrandComicsDatabase:betafrom
ProfNardi:fix/catalog-homepage-series-search

Conversation

@ProfNardi

@ProfNardi ProfNardi commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Changes

  • Guard homepage creator timeline queries with USE_TEMPLATESADMIN, matching the template's rendering condition. When enabled, the existing selection and aggregation logic is preserved.

  • Fetch matching series IDs separately for:

    • series names
    • issue titles
  • Combine the matching IDs using a Python set union. This avoids both the reverse-relation join and an OR condition containing a subquery.

  • Materialize matching IDs once per request so filtering, pagination, and table rendering don't repeat the text search.

  • Preserve substring matching against series names and issue titles.

  • Use select_related() for the foreign-key relationships consumed by the results table.

  • Revert the changes to Series.display_publication_dates().

  • After issue deletion:

    • check first_issue_series_set.count()
    • check last_issue_series_set.count()
    • call set_first_last_issues() on the affected series when needed.
  • Correct the timeline comment to refer specifically to USE_TEMPLATESADMIN.

Validation

  • Both existing issue and variant deletion tests passed on the latest implementation.

  • Previously verified:

    • search-result equivalence
    • duplicate elimination
    • empty queries
    • case-insensitive matching
    • creator selection with the timeline enabled
    • absence of creator queries when the timeline is disabled
  • git diff --check passed.

  • The existing tests for the removed publication-date fallback still need to be updated.

  • The full test suite has not been validated against this revision.

Notes

  • No schema migrations or catalog data repair are included.
  • First/last issue references are updated during normal issue deletion.
  • Matching IDs are held in memory per request; memory consumption scales with the number of matching series.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request improves performance and robustness for catalog-sized homepage and series searches. It handles missing issue pointers gracefully when retrieving publication dates, conditionally disables the homepage timeline query when managed content is disabled, and optimizes series searches by querying issue titles separately to avoid expensive joins. A review comment suggests further optimizing the series search query in MySQL by fetching matching IDs for series names and issue titles separately in Python and combining them via a set union, avoiding a slow OR subquery.

Comment thread apps/gcd/views/search.py Outdated
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Comment thread apps/gcd/models/series.py Outdated
return ' ?' if flag else ''

def display_publication_dates(self):
# Catalog dumps can omit an issue referenced by these cached pointers.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of modifying the display code, we should prevent the wrong links to be created.

I ran set_first_last_issues() on all affected series, so this situation right now does not exists any more.

When an issue gets deleted, we need to check for:
issue.first_issue_series_set.count()
issue.last_issue_series_set.count()
and if True run set_first_last_issues on the series.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted the changes to display_publication_dates(). Issue deletion now checks first_issue_series_set.count() and last_issue_series_set.count() and calls set_first_last_issues() on the affected series.

Comment thread apps/gcd/views/__init__.py Outdated
break
creators = []
end_listed = 0
# The timeline is only rendered when managed content is enabled.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment should be changed, USE_TEMPLATESADMIN is different to managed content

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the timeline comment to refer to USE_TEMPLATESADMIN.

Comment thread apps/gcd/models/issue.py Outdated
Comment on lines +201 to +202
if series.pk == self.series_id:
series = self.series

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What shall this do ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the queryset returns a separate Series instance.
Reusing self.series ensures its first/last issue references are updated too, because revision statistics save that cached instance again after deletion.
Otherwise, that save restores the stale references. I verified this: removing these lines makes the deletion test fail, with first_issue pointing to the deleted issue again.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see.
Hmm, I try to avoid code for handling preventable errors.
self.series.set_first_last_issues()
would be enough for what we want to handle here, without the for loop.

There can only be more than one due to dangling first/last issue link in case of moved issue, which we should handle when moving series (I am cleaning up the existing dangled links), not having code here in a different logic place ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated as suggested: Issue.delete() now calls self.series.set_first_last_issues() directly after deletion, without the loops. Updated the tests, including a check that saving the cached series again preserves the correct references. All seven targeted tests passed on MySQL.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a concrete example in my local database: searching for “Nathan Never” crashes while rendering “Nathan Never gigant” (series ID 147088). Its first_issue_id is 2207972, but that issue is missing from my database. The series has 13 active issues, and the first by sort_code is 2207951.
Is this one of the cases covered by your cleanup? I understand your database may already be fixed while my local copy still contains the stale reference.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cleaned up the production db. With the next dump you would be fine locally as well.

@jochengcd
jochengcd merged commit 1234f23 into GrandComicsDatabase:beta Sep 25, 2026
2 checks passed
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.

2 participants