如何更有效地执行 returns 一个 ID 在其他两个表中出现多少次的查询?

How can I more efficiently perform a query that returns how many times an ID appears in two other tables?

我已经从其他来源找到了一些解决方案,但 none 对我来说似乎可以有效地执行。我正在使用 derby,我当前的解决方案需要一分钟多的时间来执行!

我正在尝试查找属于给定艺术家的歌曲和专辑的数量,并将这些数字显示在艺术家姓名和 ID 旁边的 2 个单独的列中。例如:

ID    Name        Songs    Albums
425   J. Smith    0        0
314   A. Payne    32       3
412   K. Thomas   423      35

艺术家 table 有 artist_id,歌曲 table 有 song_id 和 album_id,专辑 table 有 album_id 和 artist_id。 table 并不小。艺术家约有 1,100 条记录,歌曲约有 73,000 条,专辑约有 7,000 条。

这是我目前的解决方案:

select ar.artist_id, ar.artist_name, count(s.song_id), count(distinct(al.album_id))
from artist ar left outer join 
    (album al inner join song s 
    on al.album_id = s.album_id)
on ar.artist_id = al.artist_id 
group by ar.artist_id, ar.artist_name

有没有办法让这个查询执行得更好? ID 列都是各自 table 中的主键,因此如果我理解正确的话,它们应该已经在 derby 中建立了索引。

此查询使用派生表来获取歌曲和专辑计数

select ar.artist_id, ar.artist_name, 
    coalesce(t1.song_cnt,0), coalesce(t2.album_cnt,0)
from artist ar left join (
    select artist_id, count(*) song_cnt
    from song group by artist_id
) t1 on t1.artist_id = ar.artist_id 
left join (
   select artist_id, count(*) album_cnt
   from album group by artist_id
) t2 on t2.artist_id = ar.artist_id

您可能想考虑将计数本身存储在您的数据库中并使用触发器更新它们。

如果您想在单个查询中执行此操作,我认为您最好使用子查询并加入它们。或者,您可以将其分解为几个小查询,让您的应用程序执行连接而不是 MySQL...执行小查询肯定会快很多,然后循环遍历结果以构建您的输出比你正在进行的递归内部连接。

(SELECT artist_id, COUNT(id) AS numAlbums FROM album GROUP BY artist_id) (SELECT album_id, COUNT(id) AS numSongs FROM song GROUP BY album_id)

最后...我想抛出这一点,尽管当您第一次使用数据库设计时,他们谈论规范化就像法律一样。但是当你在你的职业生涯中走得更远时,你实际上会了解非规范化,并且有时预先计算的列(例如你的计数)是可以接受的并且是快速性能所必需的。