Skip to content

fix: optimize forum migration to eliminate N+1 queries and improve scalability#58

Open
Alam-2U wants to merge 4 commits into
release-ulmofrom
ealam/LP-832
Open

fix: optimize forum migration to eliminate N+1 queries and improve scalability#58
Alam-2U wants to merge 4 commits into
release-ulmofrom
ealam/LP-832

Conversation

@Alam-2U

@Alam-2U Alam-2U commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR optimizes the MongoDB → MySQL forum migration process by eliminating several N+1 query patterns, reducing per-record database operations, and introducing batched/parallel processing capabilities.

The existing migration performed a large number of repeated database lookups and individual inserts, causing migration time to scale poorly with dataset size. Analysis showed that for large courses, the migration generated hundreds of thousands of database queries and MongoDB round trips, resulting in impractical runtimes.

Changes

User Pre-fetching

  • Replaced repeated User lookups with a single bulk fetch per course.
  • Cached users in memory and reused them throughout migration.
  • Eliminates N+1 queries for authors, voters, editors, and flaggers.

MongoContent Pre-fetching

  • Bulk-loaded all required MongoContent records for a course.
  • Reused cached objects across migration steps.
  • Removes repeated lookups performed during edit-history and flagger migration.

Bulk Creation of Forum Content

  • Replaced per-record inserts with bulk_create() for:

    • Threads
    • Comments
    • Votes
    • Edit History
    • Flaggers
    • Read States
    • User Statistics
  • Added configurable batch sizes to control memory usage and database load.

Comment Migration Improvements

  • Migrates comments in multiple passes to preserve parent-child relationships.
  • Uses bulk operations for sort_key updates instead of individual saves.

Subscription Migration Optimization

  • Replaced one MongoDB subscription query per content item with a single batched query per course using $in.
  • Significantly reduces MongoDB round trips.

Read State Optimization

  • Bulk-fetches referenced thread IDs.
  • Uses batched creation/update logic for ReadState and LastReadTime.

Parallel Course Processing

  • Added optional --workers argument.
  • Allows multiple courses to be migrated concurrently in MySQL environments.
  • Default value remains 1 to preserve compatibility and avoid issues in environments such as SQLite-based tests.

Operational Improvements

  • Added configurable --batch-size parameter.
  • Improved migration logging and per-course timing visibility.
  • Added better error isolation so failures in one course do not prevent processing of others.

Validation

  • All existing migration tests pass.
  • Migration successfully validated in a local environment.
  • SQLite concurrency issues encountered during testing were addressed by keeping parallel execution opt-in (--workers=1 by default).

Expected Impact

These changes significantly reduce:

  • Database query count
  • MongoDB round trips
  • Individual INSERT operations

The migration now relies primarily on batched reads and writes, making it substantially more scalable for large datasets and enabling effective performance testing against production-scale data.

Follow-up

The next step is validating performance improvements against a larger dataset by either:

  • Connecting a local/sandbox environment to Edge/Prod MongoDB data, or
  • Importing representative production-scale data into a sandbox environment to benchmark the actual runtime improvements and determine optimal worker and batch-size settings.

Ticket : LP-832

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the MongoDB → MySQL forum migration to reduce N+1 query patterns by prefetching users and MongoContent mappings, and by switching many per-row operations to bulk reads/writes with optional parallel per-course execution.

Changes:

  • Introduces course-wide prefetching/caching and bulk_create/bulk_update flows for threads, comments, votes, edit history, abuse flaggers, subscriptions, and read states.
  • Adds optional multi-course parallelism (--workers) and configurable bulk operation sizing (--batch-size) in the management command.
  • Bumps package version to 0.6.8.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
forum/migration_helpers.py Replaces per-record ORM work with batched caching + bulk operations for migration steps.
forum/management/commands/forum_migrate_course_from_mongodb_to_mysql.py Adds worker-based parallel course migration, batch size wiring, and improved progress reporting.
forum/init.py Version bump.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread forum/migration_helpers.py Outdated
Comment on lines +378 to +390
mc_rows = [
MongoContent(
mongo_id=mid,
content_type=thread_ct,
content_object_id=thread.pk,
)
for mid, thread in zip(mongo_ids, created)
if thread.pk
]
if mc_rows:
MongoContent.objects.bulk_create(
mc_rows, batch_size=BATCH_SIZE, ignore_conflicts=True
)
Comment on lines +40 to +48
# Ensure this thread does not reuse a connection inherited from the
# main thread (Django creates a new one on first access per thread).
connections.close_all()

# Django stores DB connections in thread-local storage, so each worker
# thread automatically gets its own connection on first access.
# Explicitly close any connection inherited from the spawning thread
# so the worker starts with a clean slate.
connections.close_all()
Comment on lines +110 to +115
create_waffle_flags = not options["no_toggle"]
workers: int = int(options["workers"]) # type: ignore[arg-type]

# Override module-level BATCH_SIZE when caller passes --batch-size.
import forum.migration_helpers as _mh
_mh.BATCH_SIZE = int(options["batch_size"]) # type: ignore[arg-type]
)
for cid, err in failed:
self.stderr.write(self.style.ERROR(f" {cid}: {err}"))
raise SystemExit(1)
Comment thread forum/migration_helpers.py Outdated
Comment on lines +561 to +564
if mc_rows:
MongoContent.objects.bulk_create(
mc_rows, batch_size=BATCH_SIZE, ignore_conflicts=True
)
@Alam-2U
Alam-2U marked this pull request as ready for review July 17, 2026 09:32
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.

3 participants