Я думаю, что это должно быть значительно быстрее (одновременно решая вашу проблему):
SELECT b.id_band, a.*, m.*
FROM band b
LEFT JOIN LATERAL (
SELECT count(*) AS ct_albums, sum(ct_songs) AS ct_songs
FROM (
SELECT id_album, count(*) AS ct_songs
FROM album a
LEFT JOIN song s USING (id_album)
WHERE a.id_band = b.id_band
GROUP BY 1
) ab
) a ON true
LEFT JOIN LATERAL (
SELECT count(*) OVER () AS ct_musicians
, name AS senior_member -- any other columns you need?
FROM member m
JOIN musician mu USING (id_musician)
WHERE m.id_band = b.id_band
ORDER BY year_death IS NOT NULL -- sorts the living first
, birth
, name -- as tiebreaker (my optional addition)
LIMIT 1
) m ON true
WHERE b.year_formed = 1981;
Получение старшего участника группы решается в LATERAL
подзапрос m
- без умножения стоимости для базового запроса. Это работает, потому что оконная функция count(*) OVER ()
вычисляется до применения ORDER BY
и LIMIT
. Поскольку у групп, естественно, всего несколько участников, это должен быть самый быстрый способ. См .:
Другая оптимизация для подсчета альбомов и песен основана на предположении, что один и тот же id_song
никогда не будет включены в несколько альбомов одной группы. Иначе они подсчитываются несколько раз. (Легко исправить и не соотносить с задачей получения старшего участника группы.)
Смысл в том, чтобы устранить необходимость в DISTINCT
на верхнем уровне после многократного умножения строк на N-стороне (мне нравится называть это "прокси кросс-соединение"). Это может привести к огромному количеству строк в производной таблице без необходимости.
Кроме того, гораздо удобнее извлечь дополнительный столбец (например, больше столбцов для старшего члена группы), чем с некоторыми другими стилями запросов.