Files
RenewCMS/docs/performance.md
T

2.0 KiB

Performance notes

The ?seo= article filter

GET /v1/article/ assesses the SEO status of articles in memory, because the status depends on the body, the site template and the authors. Every request assesses every visible article once, to fill counts.suggestions, and ?seo= reuses that assessment to filter before paging. The cost therefore grows with the number of articles, not with the page size.

TestSeoFilterPerformance in test/seo_filter_performance_test.go (skipped with -short) measures 5,000 articles of about 5 KB each in one site on a temporary SQLite file, every article with suggestions, slowest of 3 runs:

Request Time
?seo=suggestions&size=25 315 to 338 ms
default page, no ?seo= 307 to 329 ms

The target is 300 ms for 5,000 articles. Both requests sit slightly above it on the development machine, so the test logs the target but only fails above 500 ms; no cache or index was added. Re-run it with go test -tags nofrontend ./test/... -run TestSeoFilterPerformance -v -count=1 after a change to the assessment rules or the article repository.

The ?seo= filter of the grouped list

GET /v1/article/?group=story uses the same assessment. The versions whose status matches (and, with q, whose title matches: the title search runs once per request through article.Repository.FindTitleMatches) are handed to the repository as StoryFilters.VersionIDs. That set can be larger than any bind-parameter limit (SQLite accepts 32,766 parameters), so it never becomes an IN (?, …) list: the repository reads the qualifying (story_id, id) pairs and the ordered story rows with id-only projections and keeps the members of the set in memory before paging. ListByStories reads the versions of the page without their bodies and only those the caller may read; the representative's body comes from the assessment pass, which still reads every visible body because the status depends on it. TestArticleStoryListSEOFilterAtScaleSQLite covers 40,001 versions.