Reputation: 958
I have these 3 tables in my PostgreSQL database:
Basically each artist has multiple albums, and each album has multiple songs.
My query correctly returns 25 distinct artist.id's who have a song whose title begins with "The " ordered by the year of the album:
SELECT id
FROM (
-- Remove the duplicate artists
SELECT DISTINCT ON (a.id) id, row
FROM (
-- Get all matching artists
-- This is slow because there is no limit
SELECT
artist.id,
row_number() OVER(ORDER BY album.year DESC) as row
FROM artist
LEFT JOIN album ON album.artist_id = artist.id
LEFT JOIN song ON song.album_id = album.id
WHERE song.title ilike 'The %'
ORDER BY album.year DESC
) as a
) as b
ORDER BY row
LIMIT 25
However it is slow and inefficient because the innermost query has no LIMIT so it will search the entire table for all possible matches. Ideally it would stop searching when the 25 distinct artist.id's have been found.
Can this query be rewritten or optimized to execute faster?
I think window functions could speed things up here, but I haven't been able to figure out something that works.
Thanks!
Upvotes: 4
Views: 1191
Reputation: 1468
Try this one,
Select id, year
from (
SELECT DISTINCT ON (artist.id) artist.id, album.year
FROM artist
rightJOIN album ON album.artist_id = artist.id
left JOIN song ON song.album_id = album.id
WHERE song.title ilike 'The %'
ORDER BY artist.id, album.year DESC
) s
order by year desc
LIMIT 25
Upvotes: 0
Reputation: 125444
select id, year
from (
SELECT DISTINCT ON (artist.id) artist.id, album.year
FROM artist
inner JOIN album ON album.artist_id = artist.id
inner JOIN song ON song.album_id = album.id
WHERE song.title ilike 'The %'
ORDER BY artist.id, album.year DESC
) s
order by year desc
LIMIT 25
An index on song.title
can help when the ilike expression does start with a %
Upvotes: 2
Reputation: 5012
Try this, should work faster than your current query
SELECT
artist.id,
MAX( album.year ) as latest_album_date
FROM
artist
JOIN album ON album.artist_id = artist.id -- JOIN, not LEFT JOIN
JOIN song ON song.album_id = album.id -- Since you have song.title in WHERE clause, it makes no sense to make these as a LEFT JOIN
WHERE
song.title ilike 'The %'
GROUP BY
artist.id
ORDER BY
latest_album_date DESC
limit 25;
Upvotes: 0