This summarizes two queries to get the top users by solutions count, their corrected forms, simulated execution plans, and recommendations. For this video: Laravel Performance: Careful with withCount() by Povilas Korop.
SELECT
    users.*,
    (
        SELECT COUNT(*)
        FROM replies
        INNER JOIN threads ON threads.solution_reply_id = replies.id
            AND threads.author_id != replies.author_id
        WHERE
            users.id = replies.author_id
            AND replies.replyable_type = 'threads'
            AND replies.created_at > '2024-09-10 11:29:36'
            AND replies.deleted_at IS NULL
    ) AS solutions_count
FROM users
HAVING
    solutions_count > 0
ORDER BY
    solutions_count DESC
LIMIT 5;| id | select_type | table | type | possible_keys | key | rows | Extra | 
|---|---|---|---|---|---|---|---|
| 1 | PRIMARY | users | ALL | NULL | NULL | 1000000 | Using temporary; Using filesort | 
| 2 | DEPENDENT SUBQUERY | replies | ref | idx_replies_filters,author_id | author_id | 10 | Using where | 
| 2 | DEPENDENT SUBQUERY | threads | ref | idx_threads_solution,solution_reply_id | idx_threads_solution | 5 | Using where | 
        +------------+
        |   users    |
        +------------+
              |
              v
     For each user, run subquery
              |
        +------------+
        |  replies   |
        +------------+
              |
              v
        +------------+
        |  threads   |
        +------------+
              |
              v
       Count matching replies
Notes:
- Performs a full scan of users.
- Executes a dependent subquery per user → N+1 pattern.
- Can be costly on large tables.
SELECT
    users.*,
    COUNT(DISTINCT replies.id) AS solutions_count
FROM users
INNER JOIN replies ON replies.author_id = users.id
INNER JOIN threads ON threads.solution_reply_id = replies.id
    AND threads.author_id != replies.author_id
WHERE
    replies.replyable_type = 'threads'
    AND replies.deleted_at IS NULL
    AND replies.created_at > '2024-09-10 11:29:36'
GROUP BY
    users.id
HAVING
    solutions_count > 0
ORDER BY
    solutions_count DESC
LIMIT 5;| id | select_type | table | type | possible_keys | key | rows | Extra | 
|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | replies | range | idx_replies_filters,author_id | idx_replies_filters | 500000 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE | threads | ref | idx_threads_solution,solution_reply_id | idx_threads_solution | 5 | Using where | 
| 1 | SIMPLE | users | eq_ref | PRIMARY | PRIMARY | 1 | 
        +------------+
        |  replies   | <- filtered by date, type, deleted_at
        +------------+
              |
              v
        +------------+
        |  threads   | <- join on solution_reply_id
        +------------+
              |
              v
        +------------+
        |   users    | <- join on author_id
        +------------+
              |
              v
   GROUP BY user, COUNT(distinct replies)
Notes:
- Efficient for leaderboards or global top N queries.
- Uses GROUP BY with temporary table and filesort.
- Works well with proper indexes.
-- For filtering replies efficiently
CREATE INDEX idx_replies_filters
    ON replies (replyable_type, deleted_at, created_at, author_id);
-- For solution lookups
CREATE INDEX idx_threads_solution
    ON threads (solution_reply_id, author_id);| Query | Pros | Cons | 
|---|---|---|
| Subquery in SELECT | Simple to read, per-user count | Executes subquery per user (N+1), expensive on large tables | 
| JOIN + GROUP BY | Fast for global top N, single pass, leverages indexes | Temporary table + filesort may use memory on large datasets | 
Verdict:
- For a leaderboard / top 5 authors → JOIN + GROUP BY (Query 2) is strongly recommended.
- For solutions_count alongside a small filtered set of users → Subquery (Query 1) is readable but risky at scale.
- Always test with EXPLAINto see row estimates and index usage.
- Proper indexing is critical for performance.
- Query 2 scales better with millions of users and replies.