Speeding up a MySQL Query with Counting Distinct Rows and Left Joins - mysql

I'm trying to get a list of all the bands in the database a long with the number of songs and albums associated with each band. The song table is ~18,000 lines, the album table is ~3,000 lines, and the bands table is ~1,200 lines. I have indexes on BandID in both the albums and songs tables, but this query still takes about 26 seconds to run! Is there a better/faster way to get all of this information in one query?
SET SQL_BIG_SELECTS=1;
SELECT b.ID, b.Name, b.URL, b.Alpha, b.Sort, b.Image, b.Path, COUNT(DISTINCT s.ID) AS SongCount, COUNT(DISTINCT a.ID) AS AlbumCount FROM mft_bands AS b
LEFT JOIN mft_albums AS a ON a.BandID = b.ID
LEFT JOIN mft_songs AS s ON s.BandID = b.ID
WHERE b.Enabled=1 GROUP BY b.ID ORDER BY b.Name

Related

LEFT JOIN query with COUNT takes so long to execute

I have 4 tables, album, artist, song_cover and song.
Am trying to join the 3 tables to the album table and include the total number of songs within each album.
The query I have so far returns results as expected but takes almost over a minute to execute.
SELECT frco_album.*,
COUNT(frco_song.song_id) AS TotalSongs,
artist_aka, artist_address,
cover_filename
FROM frco_album
LEFT JOIN frco_song ON frco_album.album_id =
frco_song.song_album_id
LEFT JOIN frco_artist ON frco_album.album_artist =
frco_artist.artist_id
LEFT JOIN frco_song_cover ON frco_album.album_cover_id =
frco_song_cover.cover_id
GROUP BY frco_album.album_id
ORDER BY album_month DESC LIMIT 0, 20;
When I get rid of the song table LEFT JOIN song ON album.album_id = song.song_album_id and COUNT(song.song_id) AS TotalSongs, the query executes fast, as expected.
What am I doing wrong here?
EDIT: I've edited the question to include the tables and changed the query to reflect the actual rows in the tables.
The left join will multiply rows and then you condense them back using group by. Assuming that there is one artist and cover per album I would try counting the songs inside the select clause:
SELECT album.*, artist_aka, artist_address, cover_filename, (
SELECT COUNT(*)
FROM songs
WHERE song.song_album_id = album.album_id
) AS TotalSongs
FROM album
LEFT JOIN artist ON album.album_artist_id = artist.artist_id
LEFT JOIN song_cover ON album.album_cover_id = song_cover.cover_id
ORDER BY album_plays DESC
LIMIT 0, 20

query result taking time to load

I have a query that fetches data from Six tables but it takes too much time to fetch data.The browser loads and shows sometimes nothing as a result.When I run this query in the MySQL database, it takes a long time to execute.
SELECT SQL_CALC_FOUND_ROWS movies.*,
curriculums.name AS curriculum,
teachers.name AS teacher,
movie_sub_categories.name AS sub_cat_name,
movie_categories.name AS cat_name
FROM movies
LEFT JOIN curriculums on movies.curriculum_id = curriculums.id
LEFT JOIN teachers on movies.teacher_id = teachers.id
LEFT JOIN movies_movie_sub_categories on movies.id = movies_movie_sub_categories.movie_id
LEFT JOIN movie_sub_categories on movies_movie_sub_categories.movie_sub_category_id = movie_sub_categories.id
LEFT JOIN movie_categories on movie_sub_categories.movie_category_id = movie_categories.id
ORDER BY id LIMIT 0, 50
Here all of my table structure
That's not a very exciting query -- it simply delivers the first 50 rows of whichever table id belongs to. When JOINing, please qualify columns so we know what is going on.
Do you really need LEFT?
Assuming you need LEFT and id belongs to movies, then this should run a lot faster:
Meanwhile, find how many rows there are in movies only once, so you don't have to compute it every time.
SELECT movies.*, curriculums.name AS curriculum,
teachers.name AS teacher, movie_sub_categories.name AS sub_cat_name,
movie_categories.name AS cat_name
FROM ( SELECT id FROM movies ORDER BY id LIMIT 0, 50 ) AS m
JOIN movies USING(id)
LEFT JOIN curriculums AS c ON movies.curriculum_id = c.id
LEFT JOIN teachers AS t ON movies.teacher_id = t.id
LEFT JOIN movies_movie_sub_categories AS mmsc ON movies.id = mmsc.movie_id
LEFT JOIN movie_sub_categories AS msc ON mmsc.movie_sub_category_id = msc.id
LEFT JOIN movie_categories AS mc ON msc.movie_category_id = mc.id
ORDER BY m.id
Please use SHOW CREATE TABLE; we need to see if you have sufficient indexes, such as
mmsc: INDEX(movie_id)
the table movies_movie_sub_categories needs to have an index on movie_id and a separate index on movie_sub_category_id. Without those two indexes the query builder will be forced to scan every record twice (since the query has two separate join clauses that reference that table)

What does this inner join query exactly mean?

I'm often on this site to find answers and I usualy find what I look for but this time it's really particular so I post.
I'm working on a code I didn't write and I'd like somebody to explain me in detail what does the following query mean :
SELECT count(*)
FROM ( SELECT Id_dormir
FROM (dormir INNER JOIN dormir_photo AS DP
ON Id_dormir = Id_dormir_photo) INNER JOIN communes as C ON
Commune_dormir = Id_commune
WHERE Type_dormir=3
GROUP BY Id_dormir, Commune_dormir ) AS T
I'l not a boss in mysql and all those inner join and as are not very clear (it's a query from a search engine.
If anyone can help, many thanks,
Laurent
The outer query count a number of rows, returned by inner query:
SELECT Id_dormir FROM dormir
INNER JOIN dormir_photo AS DP ON Id_dormir = Id_dormir_photo
INNER JOIN communes as C ON Commune_dormir = Id_commune
WHERE Type_dormir=3 GROUP BY Id_dormir, Commune_dormir
In this query author get information from 3 tables:
domir, domir_photo, but only rows, where Id_dormir_photo = Id_dormir and from communes rows, where Commune_dormir = Id_commune. Than he filter rows with Type_dormir=3 and groups this with Id_dormir, Commune_dormir to have only UNIQUE rows with Id_dormir, Commune_dormir.
Your query count rows, where unique pair of Id_dormir, Commune_dormir and isset records in dormir_photo and communes.
I recommend you to read about different types of JOIN operation, especially about INNER JOIN (standard JOIN) and LEFT JOIN, this types are most applicable.

Sorting results from joins

While running this query:
SELECT
a.id,
pub.name AS publisher_name,
pc.name AS placement_name,
b.name AS banner_name,
a.lead_id,
a.partner_id,
a.type,
l.status,
s.correctness,
a.landing_page,
t.name AS tracker_name,
a.date_view,
a.date_action
FROM actions AS a
LEFT JOIN publishers AS pub ON a.publisher_id = pub.id
LEFT JOIN placements AS pc ON pc.publisher_id = pub.id
LEFT JOIN banners AS b ON b.campaign_id = a.campaign_id
LEFT JOIN leads l ON
l.lead_id = a.lead_id
AND l.created = (
SELECT MAX(created) from leads l2 where l2.lead_id = l.lead_id
)
LEFT JOIN statuses AS s ON l.status = s.status
LEFT JOIN trackers AS t ON t.id = a.tracker_id
LIMIT 10
I am able to sort by every column from actions table. However when I try to for example ORDER BY b.name (from banners table, joined on actions.banner_id) or ORDER BY l.lead_id (joined from leads on more complex condition as seen above) MySQL is running query for a loooong time (most tables have tens of thousands records). Is it possible, performance-wise, to sort by joined columns?
You should rewrite the query with a inner join on the table where the column you want to sort on is.
For example, if you sort on actions.banner_id
SELECT ...
FROM actions AS a
JOIN banners AS b ON b.campaign_id = a.campaign_id
LEFT JOIN *rest of the query*
You will get the same results unless there is not enough banners that can be joined to action to produce a total of 10 rows.
I'm guessing it's not the case otherwise you wouldn't be sorting on banner_id.
You could first filter (order by, where, etc.) your records in a subquery and then join the result with the rest of the tables.

MySQL: get records from database and add a COUNT() column to the rows

I'm trying to retrieve books from one table and left join the chapters table. What I need from the second table is just the COUNT() of chapters available for those books and add that value as an extra column called chapters (or something else).
My current try looks like this:
SELECT b.*, count(c.chapter_nr) as chapters FROM books as b left join chapters as c on c.book_id = b.id
This only gets one from from the books table and adds the count() result to that row, but I'd like to get ALL the rows from the books table, hence the LEFT JOIN
SELECT b.*, count(c.chapter_nr) as chapters
FROM books as b
LEFT JOIN chapters as c on (c.book_id = b.id)
GROUP BY b.id
EXPLANATION
You need to group by the book in order to determine the actual chapter counts. If you were to leave out the GROUP BY clause, you would be retrieving a resultset of all chapters of every book. You simply want to limit the results to unique books and their corresponding chapter counts.
You are missing the GROUP BY clause:
SELECT b.*, count(c.chapter_nr) as chapters
FROM books AS b
LEFT JOIN chapters AS c ON c.book_id = b.id
GROUP BY b.id
Try :
SELECT b.*,
(select count(*) from chapters c where c.book_id = b.id) as chapters
FROM books b
This will return 0 if there are no chapters for a book.
Untested, but you need a "group by" clause to do what you want:
Select b.*, count(*) as chapters
from books b left outer join chapters c
on c.book_id = b.id
group by b.*