Pular para o conteúdo principal
2026-09-23PurePlayerDesempenho medidoBibliotecas grandes

Testes de desempenho do espelho de leitura do PurePlayer: paginação profunda em menos de um segundo para 500.000 faixas

O PurePlayer inclui uma camada de leitura em espelho baseada em SQLite para coleções de grande porte. Em um ambiente com 500.000 faixas, o tempo de paginação profunda cai para menos de um segundo e a navegação pelo índice A-Z opera em milissegundos de dígito único. A indexação inicial leva cerca de 30 minutos e ocupa 2 GB de armazenamento local, gerenciável em Ajustes.

Testes de desempenho do espelho de leitura do PurePlayer: paginação profunda em menos de um segundo para 500.000 faixas

Quando uma biblioteca local atinge centenas de milhares de faixas, a rolagem das primeiras telas costuma permanecer fluida, mas a paginação profunda, a navegação alfabética e as buscas globais passam a apresentar latências expressivas. Utilizando uma base de referência com 500.500 faixas, analisamos os tempos de execução dos principais caminhos de leitura e implementamos um espelho local de leitura em SQLite planejado para a versão 7.0.

Nota de versão: a versão 6.0 já trouxe melhorias estruturais de desempenho. O espelho de leitura aqui apresentado é voltado para a versão 7.0 e encontra-se em testes internos. Todos os números foram coletados em compilações internas de desenvolvimento.

A solução mantém uma cópia derivada em SQLite da biblioteca localmente. Na fase de indexação, chaves de ordenação, atributos de filtragem e âncoras de índice A-Z são pré-calculados e gravados em disco. O armazenamento nativo mantém o controle dos dados de referência, enquanto o espelho atende às consultas frequentes, permitindo operações independentes de reconstrução ou limpeza.

Resultados dos testes de desempenho

Os testes foram executados em um Mac mini M4 com a base de 500.500 faixas, passando por validação de consistência campo a campo:

Caminho de leitura Escala Armazenamento nativo Espelho Ganho
Criação de snapshot da lista 10k 3030 ms 21 ms ~143×
Paginação de lista (com filtros) 10k 1984 ms 8,2 ms ~242×
Salto de âncora A-Z 10k ~2050 ms 0,4–7,6 ms 274–5100×
Página profunda (offset 450k) 500k ~28 min/página ~0,9 s ~1800×
Varredura sem resultados «linhas visíveis» 100k 98,1 s 46 ms ~2100×
Candidatos multicritério em listas inteligentes 100k 6,9 s 1,27 s ~5,4×
Tela de playlist / detalhe de artista / primeira exibição 50k – – 4,5–7,3×

Na escala de 500.000 faixas, o caminho nativo realiza varreduras completas da tabela, elevando a duração conforme a profundidade da busca: consultar uma página na altura da faixa 400.000 consumia cerca de 1668 segundos na referência. O espelho reduz esse tempo para entre 0,8 e 1,4 segundo, proporcionando tempos de resposta consistentes em qualquer nível de deslocamento.

Etiquetas de ordenação e compatibilidade de telas

Para estilos como música clássica e jazz, ouvintes costumam habilitar etiquetas de ordenação (Sort Tags) para classificar «The Beatles» sob a letra B («Beatles, The»). O espelho mantém dois conjuntos de chaves de ordenação para os cinco campos compatíveis. Alternar as etiquetas apenas seleciona a coluna equivalente na consulta SQL, mantendo a régua A-Z atualizada sem exigir nova geração de índices.

Telas consolidadas de álbuns, artistas e compositores também usam as consultas do espelho. No entanto, com etiquetas ativadas nessas telas, o sistema recorre ao armazenamento nativo para reproduzir os valores individuais de cada entidade com exatidão. O desenvolvimento de tabelas consolidadas no fluxo de gravação está programado para as próximas versões.

Uso de recursos e compromissos

O uso do espelho local requer tempo de indexação e espaço em disco:

  • Tempo de geração: a indexação completa roda em segundo plano. Para 500.000 faixas, a geração inicial dura cerca de 32 minutos, mantendo a navegação ativa no modo padrão; bibliotecas com 50.000 faixas completam em aproximadamente 35 segundos.
  • Espaço em disco: o arquivo de espelho para 500.000 faixas ocupa por volta de 2,1 GB de armazenamento local. A tela de Ajustes detalha a ocupação real; ao desativar o recurso, os arquivos são mantidos para reativação imediata, existindo também a opção de exclusão manual total.
  • Sobrecarga de gravação: atualizações de metadados sincronizam o espelho em tempo real, acrescentando cerca de 20 ms por confirmação de lote em nossas medições.

Em virtude desse perfil de consumo, o recurso vem desativado de fábrica, permitindo ativação sob demanda conforme o tamanho da biblioteca do usuário.

Mecanismos centrais de otimização

  • Projeção de valores leves: enquanto o fluxo padrão cria objetos gerenciados completos para cada registro, o espelho lê linhas brutas do SQLite e as projeta em tipos leves, contendo os ciclos de vida de memória e CPU.
  • Empurramento de predicados: regras de filtragem, critérios de ordenação e eliminação de duplicatas rodam diretamente no motor de banco de dados, filtrando os registros antes de carregá-los na memória.
  • Pré-cálculo de chaves de ordenação e índices: chaves normalizadas e caracteres do índice A-Z são gravados no momento da indexação. As consultas utilizam paginação por chaves (Keyset Pagination) e leituras diretas de índice, estabilizando as respostas em páginas profundas.

Consistência de dados e detalhes de implementação

Para garantir paridade total entre o espelho e o armazenamento principal, o conjunto de testes executou combinações de 19 colunas de ordenação, direções ascendente e descendente, estados de etiquetas e filtros compostos. Diversos detalhes de fronteira foram ajustados:

  • Coalescência de nulos e cadeias vazias: as regras de etiquetas priorizam o valor da tag e usam o nome de exibição caso ela não exista. Considerando que operadores do Swift e funções SQL tratam sequências vazias de formas distintas, o espelho separa as chaves em colunas próprias e as define explicitamente nas consultas.
  • Ordenação em campos legados: a duração de faixas era classificada historicamente por comparação alfanumérica de texto (como «120.0» antes de «90.0»). Para manter a ordenação original, os campos de texto contam com chaves próprias de ordenação textual, deixando índices numéricos para colunas estritamente numéricas.
  • Alinhamento de caracteres de espaço: as definições de espaços em branco no Swift divergem sutilmente das funções usuais de remoção de espaços em SQL. Marcadores de estado gravados no banco foram inseridos para uniformizar a detecção de conteúdo vazio.
  • Divisão em lotes em grandes volumes: ao processar 500.000 registros, gatilhos de busca textual gravam múltiplos índices, demandando cerca de 32 minutos no total. O fluxo de geração foi estruturado em lotes com suporte a retomada após pausas.
  • Arbitragem de gravações paralelas: para alterações de metadados ocorridas durante a indexação, cada gravação recebe um marcador sequencial estritamente crescente, permitindo que regras de concorrência apliquem as versões mais recentes sem inconsistências.

Todos os números foram obtidos em compilações de depuração; relatórios de medição e rotinas de teste estão preservados no repositório.