navidrome/db/migrations
Deluan Quintão 5ec6e6a8d4
fix(opensubsonic): make search3 empty-query pagination fast at large offsets (#5601)
* fix(subsonic): make search3 empty-query pagination fast at large offsets

Empty-query search3 (used by clients like Symfonium to sync the whole
library) degraded linearly with songOffset: the offset optimization in
optimizePagination keeps the original query's LEFT JOINs (annotation,
bookmark, library) inside its rowid NOT IN subquery, making it as slow as
plain OFFSET (~5s per page at offset 900K on a 920K-track library).

Rewrite the empty-query branch of doSearch to use the same two-phase
approach as the FTS search: Phase 1 paginates rowids on the bare main
table, which SQLite satisfies with a covering index at any offset; Phase 2
hydrates only the page's rows with all JOINs. The Phase 2 hydration logic
is extracted into hydrateRowidPage, now shared with ftsSearch.execute.

Also replace the media_file_missing index with a composite covering index
on (missing, library_id), so Phase 1 stays covering for non-admin users,
whose queries include a library_id filter. The composite serves all
missing-only lookups via its prefix.

With a 920K-track / 85K-album test library, search3 empty-query responses
are now flat (~0.1s) at every offset, for both admin and non-admin users
(previously 3-5s at offsets above 600K).

* refactor(persistence): share search Phase 1 contract and dedup junction fan-out

Extract the Phase 1 query assembly that was duplicated between the FTS
search and the empty-query search into executeTwoPhase: both paths now
supply only their strategy-specific FROM/JOINs and ORDER BY, while the
shared contract (missing filter, library access, options.Filters, and
Max/Offset semantics) lives in one place.

Also fix a pagination integrity bug: the artist library filter joins the
library_artist junction table, so an artist present in multiple libraries
produced duplicate rowids in Phase 1, corrupting offset-based pagination
(short pages and repeated artists during full-library syncs). Phase 1 now
applies DISTINCT whenever a junction-based LibraryFilter is set. DISTINCT
is used instead of GROUP BY because bm25() cannot be evaluated in a
grouped query; plain-filter tables (media_file, album) skip the dedup so
their Phase 1 keeps the streaming covering-index plan. This also fixes the
same duplication in the pre-existing FTS search path.

* fix(persistence): pin artist search Phase 1 join order with CROSS JOIN

search3 always filters artists by library (library_artist.library_id IN
...), and with the junction JOIN in the search Phase 1 rowid query SQLite
chose to drive from library_artist, sorting every junction row with a temp
b-tree on each page — a flat ~200ms penalty per request at 405K artists,
even at offset 0 (the previous code avoided this by accident: its GROUP BY
artist.id pinned an artist-driven plan).

Use CROSS JOIN (SQLite's explicit join-order override) in a search-only
variant of the artist library filter, keeping artist as the outer table so
Phase 1 streams rowids in artist.id order from the primary key index and
LIMIT/OFFSET short-circuits. The DISTINCT dedup stays and costs nothing
under the streaming plan. Other artist queries keep the planner's freedom.

With 405K artists, empty-query artist search is now 0.07s at offset 0 and
0.25s at offset 399K end-to-end (was 0.31s/0.34s before this fix, and up
to 1.2s on master at deep offsets). Artist FTS text search is unaffected.
2026-06-12 15:53:37 -04:00
..
20200130083147_create_schema.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200131183653_standardize_item_type.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200208222418_add_defaults_to_annotations.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200220143731_change_duration_to_float.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200310171621_enable_search_by_albumartist.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200310181627_add_transcoding_and_player_tables.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200319211049_merge_search_into_main_tables.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200325185135_add_album_artist_id.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200326090707_fix_album_artists_importing.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200327193744_add_year_range_to_album.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200404214704_add_indexes.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200409002249_enable_search_by_tracks_artists.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200411164603_add_created_and_updated_fields_to_playlists.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200418110522_reindex_to_fix_album_years.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200419222708_reindex_to_change_full_text_search.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200423204116_add_sort_fields.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200508093059_add_artist_song_count.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200512104202_add_disc_subtitle.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200516140647_add_playlist_tracks_table.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200608153717_referential_integrity.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200706231659_add_default_transcodings.go feat(bfr): Big Refactor: new scanner, lots of new fields and tags, improvements and DB schema changes (#2709) 2025-02-19 20:35:17 -05:00
20200710211442_add_playlist_path.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200731095603_create_play_queues_table.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200801101355_create_bookmark_table.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20200819111809_drop_email_unique_constraint.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20201003111749_add_starred_at_index.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20201010162350_add_album_size.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20201012210022_add_artist_playlist_size.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20201021085410_add_mbids.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20201021093209_add_media_file_indexes.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20201021135455_add_media_file_artist_index.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20201030162009_add_artist_info_table.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20201110205344_add_comments_and_lyrics.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20201128100726_add_real-path_option.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20201213124814_add_all_artist_ids_to_album.go Refactor string utilities into its own package str 2024-06-05 22:09:27 -04:00
20210322132848_add_timestamp_indexes.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20210418232815_fix_album_comments.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20210430212322_add_bpm_metadata.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20210530121921_create_shares_table.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20210601231734_update_share_fieldnames.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20210616150710_encrypt_all_passwords.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20210619231716_drop_player_name_unique_constraint.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20210623155401_add_user_prefs_player_scrobbler_enabled.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20210625223901_add_referential_integrity_to_user_props.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20210626213026_add_scrobble_buffer.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20210715151153_add_genre_tables.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20210821212604_add_mediafile_channels.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20211008205505_add_smart_playlist.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20211023184825_add_order_title_to_media_file.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20211026191915_unescape_lyrics_and_comments.go Refactor string utilities into its own package str 2024-06-05 22:09:27 -04:00
20211029213200_add_userid_to_playlist.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20211102215414_add_alphabetical_by_artist_index.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20211105162746_remove_invalid_artist_ids.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20220724231849_add_musicbrainz_release_track_id.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20221219112733_add_album_image_paths.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20221219140528_remove_cover_art_id.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20230112111457_add_album_paths.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20230114121537_touch_playlists.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20230115103212_create_internet_radio.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20230117155559_add_replaygain_metadata.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20230117180400_add_album_info.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20230119152657_recreate_share_table.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20230202143713_change_path_list_separator.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20230209181414_change_image_files_list_separator.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20230310222612_add_download_to_share.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20230404104309_empty_sql_migration.sql Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20230515184510_add_release_date.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20230616214944_rename_musicbrainz_recording_id.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20231208182311_add_discs_to_album.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20231209211223_alter_lyric_column.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20240122223340_add_default_values_to_null_columns.go.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20240426202913_add_id_to_scrobble_buffer.go Fix migration package name mismatch 2024-05-08 19:54:48 -04:00
20240511210036_add_sample_rate.go Add sampleRate to the DB 2024-05-11 17:57:45 -04:00
20240511220020_add_library_table.go feat(bfr): Big Refactor: new scanner, lots of new fields and tags, improvements and DB schema changes (#2709) 2025-02-19 20:35:17 -05:00
20240629152843_remove_annotation_id.go Remove unnecessary annotation table primary key 2024-06-29 11:45:41 -04:00
20240802044339_player_use_user_id_over_username.go Use userId in player, other fixes (#3182) 2024-08-03 13:37:21 -04:00
20241020003138_add_sort_tags_index.sql perf(server): add index for sort tags. 2024-10-19 20:46:54 -04:00
20241024125533_fix_sort_tags_collation_and_index.sql fix(server): fix case-insensitive sort order and add indexes to improve performance (#3425) 2024-10-26 14:06:34 -04:00
20241026183640_support_new_scanner.go refactor: rename chain package to run and update references 2025-06-14 17:19:06 -04:00
20250522013904_share_user_id_on_delete.sql fix(db): allow deleting users that have shares (#4098) 2025-05-21 22:16:10 -04:00
20250611010101_playqueue_current_to_index.go feat(server): add index-based play queue endpoints to native API (#4210) 2025-06-10 23:00:44 -04:00
20250701010101_add_folder_hash.go feat(scanner): add folder hash for smarter quick scan change detection (#4220) 2025-06-12 13:17:34 -04:00
20250701010102_add_annotation_user_foreign_key.sql fix(db): add user foreign key constraint to annotation table (#4211) 2025-06-13 17:27:57 -04:00
20250701010103_add_library_stats.go fix(scanner): filter folders by num_audio_files to ensure accurate statistics 2025-06-23 10:26:26 -04:00
20250701010104_make_replaygain_fields_nullable.go fix: Allow nullable ReplayGain and support 0.0 (#4239) 2025-06-17 12:02:25 -04:00
20250701010105_remove_dangling_items.sql fix(db): clear dangling music from BFR upgrade (#4262) 2025-06-28 18:43:11 -04:00
20250701010106_add_participant_stats_to_all_artists.sql feat(server): expose main credit stat to reflect only album artist | artist credit (#4268) 2025-06-28 19:00:13 -04:00
20250701010107_add_mbid_indexes.sql feat: MBID search functionality for albums, artists and songs (#4286) 2025-06-30 17:11:54 -04:00
20250701010108_add_multi_library_support.go feat: Multi-library support (#4181) 2025-07-18 18:41:12 -04:00
20250823142158_make_playqueue_position_int.sql fix(db): make playqueue position field an integer (#4481) 2025-11-06 14:41:09 -05:00
20251109010105_add_annotation_rating_date.sql feat: add Rated At field - #4653 (#4660) 2025-11-24 23:18:05 -05:00
20251206013022_create_scrobbles_table.sql feat(server): track scrobble/linstens history (#4770) 2025-12-06 11:07:18 -05:00
20260104203627_playlist_case_insensitive_name.sql fix(ui): make playlist name sorting case-insensitive (#4845) 2026-01-05 19:05:11 -05:00
20260106000620_create_plugin_table.sql feat(plugins): New Plugin System with multi-language PDK support (#4833) 2026-01-14 19:22:48 -05:00
20260117201522_add_avg_rating_column.sql feat(subsonic): Add avgRating from subsonic spec (#4900) 2026-01-18 17:42:42 -05:00
20260220173400_add_fts5_search.go feat(server): implement FTS5-based full-text search (#5079) 2026-02-21 17:52:42 -05:00
20260228020813_add_plugin_allow_write_access.sql feat(plugins): allow mounting library directories as read-write (#5122) 2026-02-28 10:59:13 -05:00
20260228172956_add_playlist_image_file.go feat(playlist): add custom playlist cover art upload (#5110) 2026-03-01 14:07:18 -05:00
20260302021413_rename_playlist_image_fields.go feat(playlist): support #EXTALBUMARTURL directive and sidecar images (#5131) 2026-03-02 11:39:59 -05:00
20260307175815_add_codec_and_update_transcodings.go feat(subsonic): implement OpenSubsonic Transcoding extension (#4990) 2026-03-08 23:57:49 -04:00
20260309120007_fix_probe_data_null.go fix(db): recreate probe_data column as NOT NULL with empty string default 2026-03-09 08:06:06 -04:00
20260309203355_ensure_default_transcodings.go fix(db): check both name and target_format in default transcodings migration (#5175) 2026-03-12 11:39:31 -04:00
20260310113858_fix_aac_transcode_command.go fix: use ADTS for AAC transcoding, temporarily exclude AAC from transcode decisions (#5167) 2026-03-11 09:26:32 -04:00
20260315233131_add_artist_uploaded_image.go feat: add artist image uploads and image-folder artwork source (#5198) 2026-03-15 22:19:55 -04:00
20260316000000_normalize_timestamps.sql fix(db): normalize timestamps and fix recently added album sorting (#5176) 2026-03-16 07:55:22 -04:00
20260318182414_add_radio_uploaded_image.go feat(ui): add cover art support for internet radio stations (#5229) 2026-03-18 18:57:33 -04:00
20260405124200_fix_schema_inconsistencies.sql fix(db): resolve schema inconsistencies in library_artist and scrobble_buffer tables (#5047) 2026-04-05 12:56:32 -04:00
20260410201914_fix_zero_album_created_at.sql fix(subsonic): always emit required created field on AlbumID3 (#5340) 2026-04-10 19:29:20 -04:00
20260513173954_move_ss_before_input.go fix(transcoding): place -ss before -i for fast input seeking (#5492) 2026-05-13 17:17:20 -03:00
20260520211813_add_media_file_artists_composite_index.sql fix(smartplaylists): optimize smart playlist performance for role and tag criteria (#5515) 2026-05-22 18:00:13 -03:00
20260612171826_add_media_file_missing_library_id_index.sql fix(opensubsonic): make search3 empty-query pagination fast at large offsets (#5601) 2026-06-12 15:53:37 -04:00
migration.go feat: add DevOptimizeDB flag to control SQLite optimization 2025-11-25 19:49:03 -05:00