Home > Enterprise >  MySQL COUNT in subquery very slow
MySQL COUNT in subquery very slow

Time:01-04

There seem to be already a lot of questions/answers to what I'm experiencing, but I couldn't adapt anything I discovered in order to fix my problem.

A have a courses table, and another views table.

The views table is meant to track page views of all the site's modules, for example:

id table id_row ip created_at
1 courses 57 xx timestamp
2 blog 12 xx timestamp

In our CMS, we are trying to get all the courses to a table, while getting their viewcount, but that viewcount is taking too long to render, as there are hundreds of courses and thousands of views.

Here's a simplified version of my query:

SELECT c.*,
(
    SELECT COUNT(*) FROM t_applications AS a
    WHERE a.id_course = c.id
    GROUP BY a.id_course
) AS applications,
(
    SELECT COUNT(*)
    FROM t_views AS v
    WHERE v.table = 'courses'
    AND v.id_row = c.id
    GROUP BY v.id_row
) as views
FROM t_courses AS c;

I've tried switching it up with JOIN and other techniques, but nothing seems to work.

Would appreciate some insight on how to improve this query's performance, as it's taking over a minute to render.

CodePudding user response:

Running a subquery in a SELECT clause is often very slow (I'm not sure but I think it runs the subquery for each row of the main query).

Using a JOIN should be more efficient as there would be a single query:

SELECT c.*,
    COUNT(DISTINCT a.id_course) AS applications,
    COUNT(DISTINCT v.id_row) as views
FROM t_courses AS c
    LEFT JOIN t_applications AS a ON c.id = a.id_course
    LEFT JOIN t_views AS v ON c.id = v.id_row
WHERE v.table = 'courses'
GROUP BY c.id;

The use of DISTINCT in the COUNT replaces your GROUP BY in the subqueries and will avoid to count the same t_applications/t_views rows multiple time.
The use of LEFT JOIN (instead of INNER JOIN) ensures that you get every rows from t_courses even if there's no matching row in the joined tables.
The ending GROUP BY is needed as a join will duplicate your t_courses rows (combination of rows between joined tables).

CodePudding user response:

Indexes:

a:  INDEX(id_course)  -- or is it the `PRIMARY KEY`?
v:  INDEX(table, id_row)  --  (in either order)

For further discussion, please provide SHOW CREATE TABLE; we need to see the indexes, datatypes, engine, etc.

  •  Tags:  
  • Related