Lorsque le volume d’une bibliothèque musicale atteint plusieurs centaines de milliers de titres, le défilement du premier écran reste généralement fluide, tandis que la pagination en profondeur, la navigation alphabétique et les recherches globales accumulent une latence notable. À partir d’un jeu de données de référence de 500 500 morceaux, nous avons mesuré les temps d’exécution des principaux chemins de lecture et mis en place un mécanisme de miroir local en lecture seule prévu pour la version 7.0.
Note de version : la version 6.0 intègre déjà des optimisations de performances fondamentales. Le miroir de lecture présenté ici cible la version 7.0 et fait l’objet de tests internes. L’ensemble des indicateurs est issu d’environnements de compilation internes.
Cette architecture produit localement une copie dérivée en lecture seule de la bibliothèque au format SQLite. Durant l’indexation, les clés de tri, les critères de filtrage et les ancres d’index A-Z sont précalculés puis enregistrés sur disque. Le stockage système conserve l’autorité sur les données sources, tandis que le miroir en lecture seule prend en charge les requêtes fréquentes et autorise des opérations de reconstruction ou de nettoyage indépendantes.
Résultats de banc d’essai
Les mesures ont été réalisées sur un Mac mini M4 avec le jeu de 500 500 morceaux, chaque valeur ayant validé des contrôles de cohérence champ par champ :
| Chemin de lecture | Échelle | Stockage système | Miroir | Facteur d’accélération |
|---|---|---|---|---|
| Création du snapshot de la liste | 10k | 3030 ms | 21 ms | ~143× |
| Pagination de liste (filtrée) | 10k | 1984 ms | 8,2 ms | ~242× |
| Saut d’ancre A-Z | 10k | ~2050 ms | 0,4–7,6 ms | 274–5100× |
| Page profonde (offset 450k) | 500k | ~28 min/page | ~0,9 s | ~1800× |
| Balayage sans résultat « lignes visibles » | 100k | 98,1 s | 46 ms | ~2100× |
| Candidats multi-critères (playlists intelligentes) | 100k | 6,9 s | 1,27 s | ~5,4× |
| Vue playlist / détail artiste / premier affichage | 50k | – | – | 4,5–7,3× |
Sur une collection de 500 000 titres, le chemin de lecture d’origine dépend d’un balayage séquentiel complet : la récupération d’une page aux environs du 400 000e morceau demandait environ 1668 secondes en référence. Le miroir en lecture seule abaisse cette durée entre 0,8 et 1,4 seconde, assurant un temps de réponse stable indépendamment de la profondeur de décalage.
Étiquettes de tri et compatibilité des vues
Pour les répertoires classiques ou jazz, les utilisateurs activent couramment des étiquettes de tri (Sort Tags) afin de ranger « The Beatles » sous la lettre B (« Beatles, The »). Le miroir conserve deux séries distinctes de clés de tri pour chacun des cinq champs concernés. L’activation de cette option modifie directement la colonne ciblée dans la requête SQL sans imposer de regénération d’index, et la barre alphabétique suit automatiquement.
Les vues agrégées (albums, artistes, compositeurs) bénéficient également des requêtes accélérées par le miroir. Toutefois, lorsque les étiquettes de tri sont actives dans ces vues, le système bascule vers le chemin de stockage principal pour restituer avec exactitude les valeurs de niveau entité. Des tables d’agrégation matérialisées côté écriture figurent dans la feuille de route pour étendre le support du miroir à ces configurations.
Empreinte ressources et compromis
L’exploitation d’un miroir local en lecture seule implique un temps de génération d’index et une occupation de stockage local :
- Durée de génération : l’indexation complète s’exécute en tâche de fond. Pour 500 000 pistes, l’opération initiale requiert environ 32 minutes, la consultation standard restant accessible durant le traitement ; un catalogue de 50 000 morceaux est indexé en 35 secondes environ.
- Espace disque : les données du miroir pour 500 000 titres occupent environ 2,1 Go. Les Réglages indiquent l’espace consommé avec précision ; la désactivation de l’option conserve les fichiers pour faciliter une réactivation immédiate, tout en offrant la possibilité d’une purge complète.
- Surcharge d’écriture : l’enregistrement des métadonnées de morceaux applique une synchronisation vers le miroir, ajoutant environ 20 ms par validation de lot dans nos tests.
En raison de ces exigences matérielles, la fonctionnalité est désactivée par défaut et peut être activée manuellement selon les dimensions de la bibliothèque.
Mécanismes clés d’optimisation
- Projection de valeurs légères : le chemin habituel instancie des graphes d’objets gérés pour chaque enregistrement ; le miroir extrait directement des lignes SQLite brutes sous forme de structures légères, réduisant les cycles CPU et la charge mémoire.
- Descente des prédicats : les règles de filtrage, les tris et la déduplication sont traités par le moteur de base de données, éliminant les volumes superflus avant le chargement en mémoire vive.
- Précalcul des clés de tri et de partitionnement : les clés normalisées et les lettres de repère A-Z sont calculées dès l’écriture. La consultation combine pagination par clés (Keyset Pagination) et balayage d’index pour préserver des délais constants en pagination profonde.
Cohérence des données et aspects d’implémentation
Pour garantir la conformité des résultats entre le miroir et le stockage principal, la suite de tests a vérifié 19 colonnes de tri, les sens ascendant et descendant, les états d’étiquettes et les combinaisons de filtres. Plusieurs spécificités techniques ont fait l’objet d’un traitement dédié :
- Gestion des valeurs nulles et chaînes vides : la règle des étiquettes applique la valeur du tag en priorité et se rabat sur le nom affiché en cas d’absence. Compte tenu des écarts d’interprétation entre les opérateurs Swift et les fonctions SQL sur les chaînes vides, le miroir sépare les clés en colonnes distinctes et les sélectionne explicitement lors de l’assemblage de la requête.
- Rétrocompatibilité du tri des durées : l’historique des bibliothèques traite la durée des pistes selon un ordre lexicographique textuel (« 120.0 » précédant « 90.0 »). Afin de conserver cet ordre, les colonnes textuelles reçoivent des clés de tri dédiées, réservant les index numériques aux attributs strictement numériques.
- Harmonisation des caractères d’espacement : les définitions des espaces en Swift (espaces insécables, tabulations, sauts de ligne) différant légèrement de la fonction de nettoyage standard SQL, un drapeau d’état côté écriture unifie la détection d’absence de contenu.
- Découpage de l’indexation massive : à l’échelle de 500 000 lignes, les déclencheurs de recherche plein texte écrivent plusieurs index et portent la durée totale à environ 32 minutes. Le traitement est scindé en tranches régulières et gère la reprise après interruption.
- Arbitrage des écritures simultanées : en cas de modification de métadonnées pendant une réindexation, chaque écriture reçoit un identifiant de séquence strictement croissant, permettant aux clauses de résolution de conflits d’assurer l’exactitude de la version finale.
L’ensemble des mesures provient de versions de développement ; les journaux détaillés et les jeux de tests sont archivés avec le projet.
