Padrão de exibição materializada

Gere visões pré-populadas sobre dados em um ou mais repositórios de dados quando os dados não estiverem formatados de maneira ideal para as operações de consulta necessárias. Essa abordagem pode dar suporte à consulta e à extração de dados eficientes e melhorar o desempenho do aplicativo.

Contexto e problema

Ao armazenar dados, os desenvolvedores e os administradores de dados geralmente priorizam como os dados são armazenados em vez de como eles são lidos. O formato de armazenamento escolhido geralmente reflete o formato dos dados, os requisitos para gerenciar o tamanho dos dados e a integridade dos dados e o tipo de armazenamento em uso. Por exemplo, quando você usa um repositório de documentos NoSQL, geralmente representa os dados como uma série de agregações, cada uma contendo todas as informações dessa entidade.

No entanto, essa abordagem pode ter um efeito negativo nas consultas. Quando uma consulta precisa de apenas um subconjunto dos dados de algumas entidades, como um resumo de pedidos para vários clientes sem todos os detalhes do pedido, ela deve extrair todos os dados das entidades relevantes para obter as informações necessárias.

Adicionar índices ou remodelar consultas em tempo de leitura nem sempre resolve essa ineficiência. Muitos repositórios não podem ser indexados novamente para padrões arbitrários de leitura sem afetar o desempenho de gravação. A agregação entre entidades permanece cara no momento da consulta. Alguns armazenamentos possuem capacidades de consulta limitadas por design. Devido a essas restrições, a otimização do caminho de leitura apenas no repositório de origem geralmente é insuficiente.

Solução

Para dar suporte à consulta eficiente, uma solução comum é gerar, com antecedência, uma exibição que materialize os dados em um formato adequado para o conjunto de resultados necessário. O padrão de Exibição Materializada descreve como gerar exibições de dados pré-preenchidos em ambientes em que os dados de origem não estão em um formato adequado para a consulta, em que é difícil gerar uma consulta adequada ou em que o desempenho da consulta é ruim devido à natureza dos dados ou do armazenamento de dados.

Nesse padrão, uma visão materializada é um modelo de leitura ou projeção que persiste dados derivados de um ou mais armazenamentos de origem. Um componente dedicado da aplicação ou um pipeline de dados pode manter a projeção, mesmo entre diferentes armazenamentos. Os consumidores da consulta tratam a projeção como somente leitura. Esse conceito de arquitetura é mais amplo do que um objeto de exibição materializada nativo do banco de dados, que um mecanismo de banco de dados define, armazena e atualiza de acordo com suas próprias restrições de recurso.

Essas exibições materializadas, que contêm apenas dados exigidos por uma consulta, permitem que os aplicativos obtenham rapidamente as informações necessárias. Além da junção de tabelas ou da combinação de entidades de dados, as exibições materializadas podem incluir os valores atuais das colunas calculadas ou dos itens de dados, os resultados da combinação de valores ou da execução de transformações nos itens de dados, além de valores especificados como parte da consulta. Uma exibição materializada pode até ser otimizada para uma única consulta.

Um ponto-chave é que uma visão materializada e os dados que ela contém são completamente descartáveis, porque podem ser integralmente reconstruídos a partir dos repositórios de dados de origem. Os consumidores da consulta não atualizam a exibição diretamente. Em vez disso, um componente dedicado, pipeline de dados ou mecanismo de banco de dados o mantém, de modo que ele é um cache especializado.

Quando os dados de origem da exibição mudam, a exibição deve ser atualizada para incluir as novas informações. Você pode agendar que essa atualização ocorra automaticamente ou quando o sistema detectar uma alteração nos dados originais. Em alguns casos, talvez seja necessário regenerar a exibição manualmente. A figura a seguir mostra um exemplo de como o padrão de visão materializada pode ser usado.

Diagrama que mostra um exemplo de como o padrão de Exibição Materializada pode ser usado.

Problemas e considerações

Considere os seguintes pontos ao decidir como implementar esse padrão:

  • Estratégia de atualização da exibição. Idealmente, a exibição é regenerada em resposta a um evento que indica uma alteração nos dados de origem, embora essa abordagem possa levar a sobrecarga excessiva se os dados de origem forem alterados rapidamente. Como alternativa, considere o uso de uma tarefa agendada, um gatilho externo ou uma ação manual para regenerar a exibição.

  • Comportamento de atualização. Determine se a implementação executa uma recompilação completa ou aplica alterações incrementalmente. Você também precisa decidir se as operações de atualização bloqueiam leituras.

    Essas decisões determinam se as consultas retornam dados materializados potencialmente obsoletos, combinam dados materializados com alterações de origem não processadas para retornar os resultados atuais ou continuam a servir a última versão completa até que a atualização seja concluída.

  • Atualize a confiabilidade do sinal. Se o sinal de ativação que dispara a regeneração da view for perdido ou atrasado — por exemplo, um evento do feed de alterações perdido ou uma falha em uma tarefa agendada — a view retornará resultados desatualizados sem aviso. Monitore a recência da atualização e alerte quando a idade da visualização exceder o limite aceitável de desatualização.

  • Atualizar custo de computação. A regeneração de uma exibição consome recursos de computação proporcionais ao volume de dados de origem e à complexidade das transformações. Para atualização acionada por eventos de dados de origem que mudam rapidamente, ou para reconstruções completas de grandes visões analíticas, o custo computacional da atualização pode ser um fator de custo significativo. Dimensione com o tamanho certo a frequência de atualização e o escopo para equilibrar a atualização de dados em relação aos gastos com computação.

  • Dependência de Event Sourcing. Em alguns sistemas, como quando você usa o padrão de Fornecimento de Eventos para manter um repositório apenas dos eventos que modificaram os dados, as exibições materializadas normalmente são necessárias. Pré-preencher exibições por meio da examinação de todos os eventos para determinar o estado atual pode ser a única maneira de obter informações do armazenamento de eventos. Se você não estiver usando Event Sourcing, considere se uma visão materializada seria útil. Visões materializadas costumam ser adaptadas especificamente para uma ou poucas consultas. Se forem usadas várias consultas, as exibições materializadas podem resultar em requisitos inaceitáveis de capacidade e custo de armazenamento.

  • Consistência de dados. Considere o impacto na consistência de dados ao gerar a exibição e ao atualizar a exibição se esse processo ocorrer em um agendamento. Se os dados de origem forem alterados ao mesmo tempo que a exibição é gerada, a cópia dos dados na exibição não será totalmente consistente com os dados originais. A janela de desatualização máxima é uma consequência direta do intervalo de atualização ou do atraso de processamento de eventos, portanto, defina a desatualização aceitável antes de escolher entre a atualização manual, agendada ou controlada por eventos.

  • Exibir o local de armazenamento. A exibição não precisa estar localizada no mesmo armazenamento ou na mesma partição como os dados originais. Você pode combinar subconjuntos de algumas partições diferentes.

  • Reconstruir em caso de perda. Uma visualização pode ser reconstruída caso seja perdida. Portanto, se a exibição for transitória e for usada apenas para melhorar o desempenho da consulta refletindo o estado atual dos dados ou para melhorar a escalabilidade, você poderá armazená-la em um cache ou em um local menos confiável.

    No entanto, se o próprio processo de atualização falhar no meio do processo — por exemplo, se uma tarefa de regeneração agendada falhar — determine se a carga de trabalho deve servir a visão completa anterior, uma visão parcialmente atualizada ou nenhuma visão até que a regeneração seja concluída com êxito.

    A abordagem mais segura é, normalmente, a publicação atômica ou a substituição com versionamento, em que sua carga de trabalho continua atendendo a solicitações e utilizando a última visualização completa enquanto você constrói e valida a nova visualização. Alterne para o novo modo de exibição após a conclusão da validação.

  • Colunas computadas. Ao definir uma exibição materializada, maximize seu valor adicionando itens de dados ou colunas com base na computação ou transformação de itens de dados existentes, em valores passados na consulta ou em combinações desses valores quando apropriado.

  • Exibir indexação. Considere indexar a exibição materializada, nos locais em que o mecanismo de armazenamento oferecer suporte para isso, para aumentar ainda mais o desempenho. Muitos bancos de dados relacionais dão suporte à indexação para exibições. No entanto, a manutenção do índice na exibição adiciona sobrecarga de caminho de gravação durante cada ciclo de atualização, portanto, balancee os ganhos de desempenho de leitura em relação ao tempo de atualização adicional e ao custo de computação.

  • Controle de acesso nas visualizações. Quando uma exibição materializada é usada para restringir quais subconjuntos de dados são visíveis para determinados consumidores, como por motivos de segurança ou privacidade, o repositório de exibição deve impor os mesmos ou mais rigorosos controles de acesso que os dados de origem. O pipeline de atualização deve excluir colunas ou linhas não intencionais, pois uma exibição que inclui acidentalmente dados além do escopo pretendido pode expor dados protegidos.

  • Ciclo de vida dos dados em visualizações. Aplique os requisitos de retenção e exclusão dos dados de origem a cada exibição materializada. Propague exclusões e tarjamentos de origem dentro do prazo exigido e inclua cada visualização no monitoramento de conformidade. Para obter mais informações, consulte linhas de base de segurança e governança de dados com Microsoft Purview.

  • Exibir o gerenciamento do ciclo de vida. Trate as definições de exibição como artefatos implantáveis gerenciados por meio do controle do código-fonte e pipelines de CI/CD, especialmente quando as exibições são definidas declarativamente. Sem o gerenciamento do ciclo de vida, as definições de visualização podem divergir entre ambientes, causando comportamentos de consulta inconsistentes nos ambientes de desenvolvimento, homologação e produção.

Quando usar esse padrão

Use esse padrão quando:

  • Você precisa criar exibições sobre dados difíceis de consultar diretamente ou onde as consultas devem ser muito complexas para extrair dados armazenados de maneira normalizada, semiestruturada ou não estruturada.
  • Você deseja criar projeções em cache recriáveis ou transitórias que melhorem o desempenho da consulta ou que moldem os dados usados para construir objetos de transferência de dados para uma interface do usuário, um relatório ou uma exibição.
  • Você precisa dar suporte a cenários com conexão intermitente ou sem conexão, em que a conexão com o armazenamento de dados nem sempre está disponível. Você pode armazenar o modo de exibição em cache localmente nesse caso.
  • Você deseja simplificar consultas e expor dados para experimentação de uma forma que não exija conhecimento do formato de dados de origem. Por exemplo, unindo tabelas diferentes em um ou mais bancos de dados ou em um ou mais domínios em armazenamentos do NoSQL e depois formatando os dados para se ajustarem ao seu uso eventual.
  • Você deseja fornecer acesso a subconjuntos específicos dos dados de origem que, por motivos de segurança ou privacidade, não devem ser geralmente acessíveis, abertos à modificação ou totalmente expostos aos usuários.
  • Você deseja fazer a ponte entre diferentes armazenamentos de dados para aproveitar suas funcionalidades individuais. Por exemplo, você pode usar um armazenamento em nuvem eficiente para gravação como armazenamento de dados de referência e um banco de dados relacional que oferece bom desempenho de consulta e leitura para manter as visões materializadas.
  • Ao usar microsserviços, mantenha-os flexívelmente acoplados, incluindo o armazenamento de dados. Views materializadas podem ajudar você a consolidar dados dos seus serviços. Se as exibições materializadas não forem apropriadas em sua arquitetura de microsserviços ou em um cenário específico, considere ter limites bem definidos que se alinham ao DDD (design controlado pelo domínio) e agregam seus dados sob demanda.

Esse padrão pode não ser adequado quando:

  • Os dados de origem são simples e fáceis de serem consultados.
  • Os dados de origem mudam muito rapidamente, ou podem ser acessados sem usar uma visualização. Nesses casos, evite a sobrecarga de processamento gerada pela criação de visualizações.
  • A consistência é uma alta prioridade. As visualizações podem nem sempre ser totalmente consistentes com os dados originais.

Design de carga de trabalho

Um arquiteto deve avaliar como o padrão Visão Materializada pode ser usado no design de suas cargas de trabalho para atender aos objetivos e princípios discutidos nos pilares do Azure Well-Architected Framework. Por exemplo:

Pilar Como esse padrão apoia os objetivos do pilar
A Eficiência de Desempenho ajuda sua carga de trabalho a atender com eficiência às demandas por meio de otimizações no dimensionamento, nos dados e no código. As exibições materializadas armazenam os resultados das consultas ou cálculos complexos sem exigir que o mecanismo do banco de dados ou o cliente recalcule todas as solicitações. Esse design reduz o consumo geral de recursos.

- PE:08 Performance de Dados

Se esse padrão introduzir compensações dentro de um pilar, considere-as em relação aos objetivos dos outros pilares.

Example

Considere um aplicativo de vendas que armazena entidades Order, OrderItem e Customer em Armazenamento de Tabelas do Azure. Os pedidos são particionados por ID do cliente, itens de pedido por ID do pedido e clientes por região. Essas chaves dão suporte aos padrões de acesso operacional do aplicativo, mas um relatório de vendas agrupado por produto deve ler dados entre partições e combiná-los no código do aplicativo.

A figura a seguir mostra uma exibição materializada que armazena o valor total de vendas e o número de clientes de compra distintos para cada produto na categoria Eletrônica. As linhas de origem e os valores de resumo são ilustrativos, não um conjunto de dados de entrada completo para os totais mostrados.

Diagrama que mostra as tabelas Order, OrderItem e Customer combinadas em um sumário materializado de vendas particionado por categoria de produto.

Um processo em segundo plano lê as entidades de origem necessárias, associa os itens do pedido aos respectivos pedidos e clientes e agrega as vendas por produto. Conta cada cliente uma vez por produto, mesmo quando esse cliente tem vários pedidos ou linhas de pedido. O processo grava os resultados em uma tabela de resumo separada, em que a categoria do produto é PartitionKey e o ID do produto é RowKey. Esta tabela de resumo é uma projeção mantida pelo aplicativo, não uma exibição materializada nativa do banco de dados.

Em seguida, um painel pode consultar a partição eletrônica em vez de repetir as leituras e agregação entre partições para cada solicitação. Uma pesquisa por um produto fornece as duas chaves. Para ver as implicações dessas chaves no desempenho das consultas, consulte Projeto para consultas.

Atualize o resumo de acordo com uma programação que atenda à janela aceitável de defasagem do relatório. Crie e valide uma nova versão antes de publicá-la, para que os leitores continuem a usar a versão completa anterior durante uma recompilação. A atualização ainda incorre em custos de leitura e agregação entre partições, mas consultas de relatório repetidas reutilizam o resultado. As alterações de origem não ficam visíveis até que uma atualização subsequente as inclua.

Próximas Etapas 

Os seguintes padrões também serão relevantes durante a implementação desse padrão:

  • Padrão de Segregação de Responsabilidade de Comando e Consulta (CQRS). Use para atualizar as informações em uma exibição materializada respondendo a eventos que ocorrem quando os valores de dados subjacentes são alterados.
  • Padrão de Fornecimento do Evento. Use junto com o padrão CQRS para manter as informações em uma exibição materializada. Quando os valores de dados de uma exibição materializada são baseados na alteração, o sistema pode gerar eventos que descrevem essas alterações e salvá-las em um repositório de eventos.
  • Padrão de Tabela de Índice. Os dados em uma exibição materializada normalmente são organizados por uma chave primária, mas talvez consultas precisem recuperar informações dessa exibição por meio da examinação de dados em outros campos. Use esse padrão para criar índices secundários em conjuntos de dados para armazenamentos de dados que não dão suporte a índices secundários nativos.