mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-01 07:21:17 +00:00
fix(db): make album ReplayGain backfill scale to large libraries
The windowed-CTE backfill was compiled as a correlated scalar subquery re-evaluated once per album (a full media_file group-by + window sort each time), which never finished on a large library. Stage the ReplayGain-bearing rows into an indexed temp table once and update only the affected albums: ~14s on a 727MB / 6945-album library, vs. effectively never.
This commit is contained in:
parent
4efd92cf83
commit
b27d6f61ae
@ -12,28 +12,25 @@ func init() {
|
||||
}
|
||||
|
||||
func upAddAlbumReplaygain(ctx context.Context, tx *sql.Tx) error {
|
||||
// Backfill the most-frequent non-null value per album, matching MediaFiles.ToAlbum. A plain
|
||||
// max() would pick a minority outlier, and GetTouchedAlbums never re-derives an unchanged album,
|
||||
// so a wrong value would persist. The CTEs group media_file once instead of scanning it per album.
|
||||
// Backfill the most-frequent value per album (matching MediaFiles.ToAlbum), staging RG-bearing rows
|
||||
// into an indexed temp table — a correlated subquery over a windowed CTE re-scans media_file per album.
|
||||
_, err := tx.ExecContext(ctx, `
|
||||
ALTER TABLE album ADD COLUMN rg_album_gain real;
|
||||
ALTER TABLE album ADD COLUMN rg_album_peak real;
|
||||
|
||||
WITH gain_mode AS (
|
||||
SELECT album_id, rg_album_gain AS val,
|
||||
row_number() OVER (PARTITION BY album_id ORDER BY count(*) DESC, rg_album_gain) AS rn
|
||||
FROM media_file WHERE rg_album_gain IS NOT NULL
|
||||
GROUP BY album_id, rg_album_gain
|
||||
),
|
||||
peak_mode AS (
|
||||
SELECT album_id, rg_album_peak AS val,
|
||||
row_number() OVER (PARTITION BY album_id ORDER BY count(*) DESC, rg_album_peak) AS rn
|
||||
FROM media_file WHERE rg_album_peak IS NOT NULL
|
||||
GROUP BY album_id, rg_album_peak
|
||||
)
|
||||
CREATE TEMP TABLE _rg_backfill AS
|
||||
SELECT album_id, rg_album_gain, rg_album_peak FROM media_file
|
||||
WHERE rg_album_gain IS NOT NULL OR rg_album_peak IS NOT NULL;
|
||||
CREATE INDEX _rg_backfill_album ON _rg_backfill(album_id);
|
||||
|
||||
UPDATE album SET
|
||||
rg_album_gain = (SELECT val FROM gain_mode WHERE gain_mode.album_id = album.id AND gain_mode.rn = 1),
|
||||
rg_album_peak = (SELECT val FROM peak_mode WHERE peak_mode.album_id = album.id AND peak_mode.rn = 1);
|
||||
rg_album_gain = (SELECT rg_album_gain FROM _rg_backfill WHERE _rg_backfill.album_id = album.id AND rg_album_gain IS NOT NULL
|
||||
GROUP BY rg_album_gain ORDER BY count(*) DESC, rg_album_gain LIMIT 1),
|
||||
rg_album_peak = (SELECT rg_album_peak FROM _rg_backfill WHERE _rg_backfill.album_id = album.id AND rg_album_peak IS NOT NULL
|
||||
GROUP BY rg_album_peak ORDER BY count(*) DESC, rg_album_peak LIMIT 1)
|
||||
WHERE album.id IN (SELECT album_id FROM _rg_backfill);
|
||||
|
||||
DROP TABLE _rg_backfill;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user