Um relatório não é inócuo pelo facto de ser de leitura. Uma consulta que percorre anos de pedidos, junta várias tabelas e agrupa por combinações abertas de filtros pode consumir CPU, memória, ligações e capacidade de disco de que a operação diária necessita. O resultado costuma surgir primeiro como lentidão intermitente: utilizadores que esperam ao guardar, processos que expiram ou filas que se acumulam enquanto alguém abre um dashboard ou solicita uma exportação.
O objetivo ao conceber relatórios analíticos em aplicações PHP não é separar todos os dados desde o primeiro dia. É decidir que carga pode coexistir com o tráfego transacional, que carga necessita de isolamento e como preservar números compreensíveis, verificáveis e seguros.
O sintoma: um relatório começa a competir com a operação

A base de dados transacional está otimizada para registar alterações corretas e consistentes: criar um pedido, reservar stock, atualizar um contrato ou registar um pagamento. As suas consultas costumam obter poucos registos através de chaves específicas e requerem dados atuais. Um relatório tem outro objetivo: detetar tendências, comparar períodos, segmentar populações ou percorrer um histórico completo.
O problema não se limita a uma consulta lenta. O padrão de concorrência também importa. Dez utilizadores que executam o mesmo painel com filtros diferentes, um descarregamento CSV com centenas de milhares de linhas e uma tarefa de fecho mensal podem gerar picos simultâneos. Em PHP, manter o pedido web aberto até terminar uma exportação agrava o impacto: ocupa processos da aplicação, pode exceder limites de tempo e proporciona uma experiência frágil se o utilizador recarregar ou perder a ligação.
Convém instrumentar antes de alterar a arquitetura. Registe duração, linhas examinadas e devolvidas, plano de execução, frequência, ligações ativas e períodos de utilização. Relacione esses sinais com métricas operacionais: latência das escritas, bloqueios, esgotamento do pool de ligações, atrasos de trabalhos e erros de timeout. Assim, distingue-se uma consulta mal construída de uma carga analítica que já não deve partilhar recursos.
Inventário de decisões, dados e tolerância ao atraso
O ponto de partida não é uma ferramenta, mas sim uma ficha por relatório. Deve indicar que decisão permite tomar, quem a toma e o que acontece se o número chegar tarde ou estiver incorreto. Um indicador para acompanhar pedidos pendentes pode exigir atualização quase imediata; uma análise de rentabilidade mensal pode aceitar dados fechados no dia seguinte.
- Audiência e permissões: equipas internas, clientes, responsáveis financeiros ou administradores.
- Granularidade: uma linha por pedido, linha de pedido, cliente, dia ou combinação agregada.
- Horizonte e volume: período consultado, crescimento esperado e número máximo de linhas exportáveis.
- Latência admissível: tempo desde a alteração na origem até surgir no relatório.
- Filtros e ordenação: campos obrigatórios, combinações livres e consultas guardadas.
- Definição de métricas: que estados contam, que moeda é utilizada, como são tratados os cancelamentos e as devoluções.
Esta ficha evita erros habituais, como utilizar a data de criação quando a pergunta exige a data de cobrança, ou somar valores de documentos anulados. Também permite declarar a atualização visível ao utilizador: «atualizado até às 10:15» é uma propriedade funcional, não um detalhe técnico oculto.
Quando a base de dados transacional é suficiente
Uma consulta à base de dados principal pode ser uma opção razoável se obtiver um conjunto limitado, utilizar índices alinhados com os seus filtros e ordenação, e a sua frequência estiver controlada. Por exemplo, listar os pedidos recentes de um cliente autenticado costuma enquadrar-se nesta categoria se filtrar pelo identificador da organização e pela data.
Reveja o plano de execução com dados representativos, não apenas com uma pequena base de dados de desenvolvimento. Evite selecionar colunas desnecessárias, aplicar funções sobre colunas filtradas quando impedem o aproveitamento de índices e paginar com offsets muito profundos. Para listagens extensas, a paginação por cursor baseada numa chave estável costuma reduzir o trabalho face a percorrer repetidamente linhas anteriores.
Os índices não são adicionados por intuição. Um índice composto deve responder aos predicados, junções e ordenação reais; cada índice adicional também torna as escritas e a manutenção mais dispendiosas. Imponha limites de intervalo, filtros obrigatórios e um máximo de resultados interativos. Se um utilizador necessitar do detalhe completo, o fluxo pode tornar-se uma exportação assíncrona em vez de forçar uma resposta HTTP longa.
Sinais para separar a carga analítica
A separação justifica-se quando o custo deixa de ser previsível ou compete com transações prioritárias. São sinais claros as agregações sobre históricos extensos, as junções entre múltiplos domínios, os filtros não antecipáveis, as ordenações de grandes conjuntos, os cálculos repetidos para muitos utilizadores e as exportações em massa. Também o é a necessidade de reter dados históricos que já não convém manter nas tabelas ativas.
Réplicas de leitura
Uma réplica reduz a pressão de leitura sobre a origem e pode servir para consultas com atraso aceitável. Não resolve automaticamente uma consulta ineficiente: continuará a consumir recursos na réplica. Além disso, é necessário assumir o atraso de replicação. Um relatório acabado de atualizar não deve prometer dados em tempo real se lê de uma cópia que ainda não recebeu a alteração.
Tabelas de resumo e armazenamentos derivados
As tabelas de resumo pré-calculam métricas por uma dimensão útil, como dia, organização e estado. Dão respostas rápidas para perguntas conhecidas, em troca de maior complexidade de atualização e menor flexibilidade. Um armazenamento derivado permite modelar consultas analíticas mais amplas e separar por completo as cargas, mas introduz sincronização, governação e custos operacionais adicionais.
Escolha a estrutura de acordo com a pergunta. Uma tabela resumida não substitui o detalhe quando um auditor necessita de explicar um número. Preserve um percurso desde o indicador agregado até aos registos de origem que o compõem, com acesso restrito quando aplicável.
Exportações assíncronas
Uma exportação deve ser modelada como trabalho: o utilizador solicita parâmetros, o PHP valida permissões e cria uma tarefa persistida, um worker gera o ficheiro e o sistema expõe o seu estado. Isto separa o pedido web da execução pesada. Defina expiração do ficheiro, limites de volume, formato, codificação e proteção do descarregamento. Não inclua dados de outras organizações por reutilizar uma consulta sem o filtro de isolamento correto.
Rastreabilidade e atualizações recuperáveis
Cada relatório deve declarar a sua fonte de verdade, a marca temporal de corte, a versão das suas regras e o tratamento de correções. Se uma venda for recalculada após uma devolução, documente se o período histórico muda, se é emitido um ajuste ou se ambos os valores permanecem visíveis. A consistência analítica exige regras explícitas, não apenas um pipeline que termine sem erros.
Os processos de atualização devem ser executados em lotes e ser idempotentes: reexecutar o mesmo lote não pode duplicar valores nem linhas. Guarde pontos de controlo, identificadores de execução, intervalo processado, contagens de entrada e saída e erros recuperáveis. Quando a origem admitir alterações tardias, processe uma janela de sobreposição ou detete registos modificados; depois, reconcilie os totais entre origem e destino para localizar divergências.
Um número útil deve responder a três perguntas: de que dados provém, com que regra foi calculado e até que momento está atualizado.
Permissões, isolamento e operação contínua

As permissões devem ser aplicadas na consulta ou na camada de acesso a dados, não confiadas ao filtro visual do painel. Cada consulta guardada, exportação diferida ou ligação de descarregamento deve voltar a validar identidade, organização e âmbito. Registe quem solicitou o relatório, com que parâmetros e quando foi gerado, sem armazenar mais dados sensíveis do que os necessários.
Por último, trate os relatórios como produto operacional: estabeleça orçamentos de tempo e custo, alerte para atrasos de atualização e teste com volumes próximos da produção. Comece com consultas e índices quando a carga estiver limitada; introduza réplicas para isolar leituras tolerantes ao atraso; utilize dados resumidos ou derivados para análises repetidas e dispendiosas; e reserve processos assíncronos para resultados que não necessitam de uma resposta imediata. Esta progressão preserva a velocidade sem perder explicabilidade.



