mirror of
https://github.com/navidrome/navidrome.git
synced 2026-10-11 20:07:11 +02:00
perf(pglite): join artist links to media files once in the stats refresh
The three counters each joined media_file_artists to media_file again, about 10 s per pass on the 97k-track library. A shared materialized artist_rows set is joined once and aggregated three times: 35 s to 25 s on roy for a full refresh, 240 ms to 138 ms per 1000-artist batch locally.
This commit is contained in:
parent
a21c4c92fc
commit
8eb9205dc8
1 changed files with 21 additions and 37 deletions
|
|
@ -487,42 +487,30 @@ func (r *artistRepository) RefreshStats(allArtists bool) (int64, error) {
|
|||
// MATERIALIZED: the correlated subquery in the UPDATE would otherwise re-run the whole
|
||||
// aggregation for every library_artist row (minutes per batch on a large library).
|
||||
batchUpdateStatsSQL := `
|
||||
WITH artist_role_counters AS MATERIALIZED (
|
||||
SELECT mfa.artist_id,
|
||||
mf.library_id,
|
||||
mfa.role,
|
||||
count(DISTINCT mf.album_id) AS album_count,
|
||||
count(DISTINCT mf.id) AS count,
|
||||
sum(mf.size) AS size
|
||||
WITH artist_rows AS MATERIALIZED (
|
||||
SELECT mfa.artist_id, mf.library_id, mfa.role, mf.album_id, mf.id, mf.size
|
||||
FROM media_file_artists mfa
|
||||
JOIN media_file mf ON mfa.media_file_id = mf.id
|
||||
WHERE mfa.artist_id ARTIST_FILTER
|
||||
GROUP BY mfa.artist_id, mf.library_id, mfa.role
|
||||
),
|
||||
artist_role_counters AS MATERIALIZED (
|
||||
SELECT artist_id, library_id, role,
|
||||
count(DISTINCT album_id) AS album_count, count(DISTINCT id) AS count, sum(size) AS size
|
||||
FROM artist_rows
|
||||
GROUP BY artist_id, library_id, role
|
||||
),
|
||||
artist_total_counters AS MATERIALIZED (
|
||||
SELECT mfa.artist_id,
|
||||
mf.library_id,
|
||||
'total' AS role,
|
||||
count(DISTINCT mf.album_id) AS album_count,
|
||||
count(DISTINCT mf.id) AS count,
|
||||
sum(mf.size) AS size
|
||||
FROM media_file_artists mfa
|
||||
JOIN media_file mf ON mfa.media_file_id = mf.id
|
||||
WHERE mfa.artist_id ARTIST_FILTER
|
||||
GROUP BY mfa.artist_id, mf.library_id
|
||||
SELECT artist_id, library_id, 'total' AS role,
|
||||
count(DISTINCT album_id) AS album_count, count(DISTINCT id) AS count, sum(size) AS size
|
||||
FROM artist_rows
|
||||
GROUP BY artist_id, library_id
|
||||
),
|
||||
artist_participant_counter AS MATERIALIZED (
|
||||
SELECT mfa.artist_id,
|
||||
mf.library_id,
|
||||
'maincredit' AS role,
|
||||
count(DISTINCT mf.album_id) AS album_count,
|
||||
count(DISTINCT mf.id) AS count,
|
||||
sum(mf.size) AS size
|
||||
FROM media_file_artists mfa
|
||||
JOIN media_file mf ON mfa.media_file_id = mf.id
|
||||
WHERE mfa.artist_id ARTIST_FILTER
|
||||
AND mfa.role IN ('albumartist', 'artist')
|
||||
GROUP BY mfa.artist_id, mf.library_id
|
||||
SELECT artist_id, library_id, 'maincredit' AS role,
|
||||
count(DISTINCT album_id) AS album_count, count(DISTINCT id) AS count, sum(size) AS size
|
||||
FROM artist_rows
|
||||
WHERE role IN ('albumartist', 'artist')
|
||||
GROUP BY artist_id, library_id
|
||||
),
|
||||
combined_counters AS MATERIALIZED (
|
||||
SELECT artist_id, library_id, role, album_count, count, size FROM artist_role_counters
|
||||
|
|
@ -532,12 +520,8 @@ func (r *artistRepository) RefreshStats(allArtists bool) (int64, error) {
|
|||
SELECT artist_id, library_id, role, album_count, count, size FROM artist_participant_counter
|
||||
),
|
||||
library_artist_counters AS MATERIALIZED (
|
||||
SELECT artist_id,
|
||||
library_id,
|
||||
jsonb_object_agg(
|
||||
role,
|
||||
jsonb_build_object('a', album_count, 'm', count, 's', size)
|
||||
) AS counters
|
||||
SELECT artist_id, library_id,
|
||||
jsonb_object_agg(role, jsonb_build_object('a', album_count, 'm', count, 's', size)) AS counters
|
||||
FROM combined_counters
|
||||
GROUP BY artist_id, library_id
|
||||
)
|
||||
|
|
@ -565,8 +549,8 @@ func (r *artistRepository) RefreshStats(allArtists bool) (int64, error) {
|
|||
placeholders[i] = "?"
|
||||
}
|
||||
filter = "IN (" + strings.Join(placeholders, ",") + ")"
|
||||
// the filter appears 4 times, so the ids are bound 4 times
|
||||
for range 4 {
|
||||
// the filter appears twice, so the ids are bound twice
|
||||
for range 2 {
|
||||
for _, id := range batch {
|
||||
args = append(args, id)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue