Counting page views
Comments enabled. I *really* need your comment
From Stack Overflow:
I have tables called
pages,page_views,page_itemsandpage_votes.The latter three tables contain a
page_idforeign key in order to keep a record of each individual view, item and vote that belongs to a page.When I query a page, I also want to retrieve
COUNT(*)frompage_views,COUNT(*)frompage_itemsandSUM(vote)frompage_votes.I have pasted a query below. It retrieves the total number of views.
SELECT Page.*, COUNT(*) AS views FROM pages AS Page INNER JOIN page_views AS PageView ON Page.id = PageView.page_id GROUP BY Page.id ORDER BY views DESC LIMIT 10 OFFSET 0I've made various attempts to add items and votes to it, but the result is either a syntax error or views/items/votes returned as an identical and
wrongnumber, probably due to the way I am joining.How can I add items and votes to this query?
On a first thought, it's simple:
SELECT
pages.
(
SELECT COUNT(*)
FROM page_views
WHERE page_views.page_id = pages.id
) AS views_count,
(
SELECT COUNT(*)
FROM page_items
WHERE page_items.page_id = pages.id
) AS items_count,
COALESCE(
(
SELECT SUM(vote)
FROM page_votes
WHERE page_votes.page_id = pages.id
), 0) AS votes_sum
FROM pages
ORDER BY
views_count DESC
LIMIT 10
| id | name | views_count | items_count | votes_sum | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 68990 | Page 68990 | 20 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 4489 | Page 4489 | 19 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 21179 | Page 21179 | 19 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 9500 | Page 9500 | 18 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 10715 | Page 10715 | 18 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 26105 | Page 26105 | 18 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 28413 | Page 28413 | 18 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 29992 | Page 29992 | 18 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 12933 | Page 12933 | 18 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 34160 | Page 34160 | 18 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 10 rows fetched in 0,0011s (1,2446s) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Can we optimize it somehow?
In this query, we select all rows from pages.
For each row, we use the subqueries in the SELECT clause to calculate the aggregates from other tables.
MySQL is even smart enough to see that items_count and votes_sum are used only in SELECT clause, so the values for them will be calculated only for first 10 rows.
But we don't really need the scan on pages. For each page, the view count may be calculated just from page_views, as it contains page_id we join on.
So we can do the following:
- Select TOP 10 viewed pages using only
page_views - Join
pageswith the resultset from the step above (will join only 10 rows) - Calculate other aggregates
SELECT pages.*,
views_count,
(
SELECT COUNT(*)
FROM page_items
WHERE page_items.page_id = pages.id
) AS items_count,
COALESCE(
(
SELECT SUM(vote)
FROM page_votes
WHERE page_votes.page_id = pages.id
), 0) AS votes_sum
FROM (
SELECT page_id, COUNT(*) AS views_count
FROM page_views
GROUP BY
page_id
ORDER BY
views_count DESC, page_id
LIMIT 10
) AS pvd,
pages
WHERE pages.id = pvd.page_id
| 68990 | Page 68990 | 20 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 4489 | Page 4489 | 19 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 21179 | Page 21179 | 19 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 9500 | Page 9500 | 18 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 10715 | Page 10715 | 18 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 26105 | Page 26105 | 18 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 28413 | Page 28413 | 18 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 29992 | Page 29992 | 18 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 12933 | Page 12933 | 18 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 34160 | Page 34160 | 18 | 40 | 180 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 10 rows fetched in 0,0019s (0,5736s) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
By joining only the results we need, we gain a 100% increase in performance.
Subscribe in a reader