/ Banco de dados

Visão simples, indexada ou materializada

Uma das formas mais comuns no emprego da visão simples é em cenários onde se deseja montar uma consulta especifica com dados pré-selecionados e deixá-la disponivel para uso futuro.
Entretanto, quando usamos na visão simples, tabelas que possuem milhares de registros, é facil perceber o aumento do custo de processamento. Caso esta visão venha a ser utilizada em consultas constantes por uma aplicação, a performance da aplicação passará a apresentar queda conforme a quantidade de registros retornados aumentam.
Uma outra opção fornecida pelos bancos e que apresenta melhor performance por permitir a criação de indices é a visão indexada ou materalizada.
Falaremos um pouco mais sobre estes dois tipos a seguir. Vamos lá!

Qual a diferença entre elas?

A visão simples é uma consulta salva em banco cujo o resultado é obtido das tabelas envolvidas na consulta de definição a cada chamada realizada.
A visão indexada/materializada obtem o resultado da mesma forma, porém este resultado é armazenado em uma estrutura de dados similar a uma tabela que inclusive pode ser indexada para melhora na performance. Este é o ponto principal e talvez o mais vantajoso no emprego deste tipo de visão. O procedimento de atualização dos dados ocorre de formas variadas conforme o SGBD usado.

Quais os custos?

A visão tradicional tem o custo de processamento do resultado apenas. Os relacionamentos ou filtros existentes na consulta de definição, dependem exclusivamente da cobertura de indices nas tabelas envolvidas. E claro, mesmo tendo esta cobertura, com o crescimento do volume de dados retornado, o custo vai aumentar.

Quanto a visão materializada, ela tem o mesmo custo que a simples e mais o custo de atualização dos seus dados conforme as tabelas envolvidas também são atualizadas. Explicando bem resumidamente, ao criar a visão, é definida a frequencia de atualização dos dados e esta operação fica a cargo do banco. Procedimentos de atualização dos dados nas tabelas de definição podem ficar mais demorados.

Comparativo

Segue em pequeno quadro comparativo entre os dois tipos.

Comparação Visão Simples Visão Materializada
Dados Gerado a cada chamada. Pré-processado e armazenado.
Atualização dos dados Em tempo real. Conforme definição feita ao criar a visão.
Velocidade para recuperar os dados Lento Rápida
Armazenamento extra? Não Sim
Pode ser indexada? Não Sim

Quando usar uma ou outra?

No caso da visão simples, o uso pode ser variado. Como exemplo, temos:

  • Consulta envolvendo diversas tabelas com filtros ou não.
  • Consulta para apresentar parte de uma tabela, limitando acesso a dados confidenciais e a tabela de origem.
  • Pode ter controle de acesso a leitura.
  • Pode servir de fonte para a emissão de relatorios ou analise de dados.

A visão indexada/materializada pode ser usada da mesma forma que a simples. Porém, ela é a melhor escolha quando desejamos obter performance. E claro, não podemos esquecer que este tipo tem um custo maior que é a parte de atualização dos dados mantida pelo banco.

Podemos encontrar alguns materiais na internet falando que o uso da visão materializada é mais indicado em situações onde as tabelas envolvidas na consulta de definição não sofram tantas mudanças. Eu, particularmente concordo. Este seria o cenário perfeito. Porém, podemos ir um pouco além e usá-la pensando somente no ganho da performance. Desde que, você esteja ciente que o seu servidor de banco não esteja rodando no vermelho e dê conta do recado.

Testando as soluções

A seguir, irei demonstrar exemplos de como criar visões indexadas ou materializadas para os bancos: SQL Server, Oracle e Postgres.

SQL Server

No inicio da pesquisa, encontrei muitos exemplos de criação da visão materializada, mas todos direcionados para o SQL Server Azure. Para a versão tradicional do SGBD, encontrei outro tipo de view chamada de visão indexada e muito similar a materializada.

Neste post, não irei entrar em detalhes sobre as opções de configuração e a maioria dos requisitos adicionais necessários para criar a visão indexada. É um conteudo importante que sugiro fazer leitura a parte. Segue o link para a consulta.

Etapas necessárias para a criação
  • Algumas opções de configuração precisam de ajustes antes de criar a visão. Elas já estão presentes no script de exemplo abaixo.
  • Verifique se a consulta de definição da visão é determinística.
  • Verifique se a consulta de definição atende os requisitos adicionais.
  • Crie a visão usando a opção WITH SCHEMABINDING.
  • Crie o índice clusterizado exclusivo na visão.

Requisitos Adicionais

Na documentação do SQL Server são vários os requisitos que precisam ser levados em conta ao criar a visão indexada. Vou listar os mais comuns:

  • As tabelas devem ser referenciadas da seguinte forma: nome_esquema.nome_tabela.
  • Funções definidas pelo o usuario devem ser criadas usando a opção WITH SCHEMABINDING.
  • Qualquer função referencia deve seguir a forma: nome_esquema.nome_função.
  • Usar somente tabelas do mesmo banco onde esta a visão.
  • Não usar: COUNT, DISTINCT, TOP, UNION/EXCEPT/INTERSECT, ORDER BY, CONTAINS, FREETEXT, tabela derivada (SELECT dentro da clausula FROM), Autojunções e Subconsultas.

O exemplo a seguir, vem com as opções de configurações ajustadas para a melhor forma:

-- Configuração de opções para criar a visão indexada
SET NUMERIC_ROUNDABORT OFF;
SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT,
   QUOTED_IDENTIFIER, ANSI_NULLS ON;
   
-- Criando a visão com schemabinding.
CREATE VIEW NOME_VISAO
    WITH SCHEMABINDING 
    AS
        SELECT ...
GO

-- Criando o indice unico e clusterizado
CREATE UNIQUE CLUSTERED INDEX NOME_INDICE
    ON NOME_VISAO (NOME_COLUNA)
GO

Com a criação do indice unico/clusterizado, o SQL Server permite que outros indices sejam criados envolvendo as demais colunas.

Oracle

Neste SGBD, a visão é chamada de visão materializada. O script a seguir, mostra um exemplo reduzido para criá-la. O Oracle dispõe de muitas outras opções. Caso precise ou tenha interesse em consultar, o link é este.

-- Normal
CREATE MATERIALIZED VIEW view-name
BUILD [IMMEDIATE | DEFERRED]
REFRESH [FAST | COMPLETE | FORCE ]
ON [COMMIT | DEMAND ]
[[ENABLE | DISABLE] QUERY REWRITE]
AS
SELECT ...;

A opção BUILD (construção da visão):

  • IMMEDIATE - a visão é populada imediatamente.
  • DEFERRED - a visão será populada na primeira requisição.

A opção REFRESH (tipos de atualização):

  • FAST - Uma atualização rápida é tentada.
  • COMPLETE - A visão é truncada e um novo preenchimento completo é feito.
  • FORCE - Uma atualização rápida é tentada. Se não for possivel, uma atualização completa é feita.

A atualização pode ser acionada de duas maneiras:

  • ON COMMIT - na atualização de dados em uma das tabelas envolvidas na consulta de definição.
  • ON DEMAND - a atualização é realizada por uma solicitação manual.

Executando o script com as opções citadas, a visão materializada é criada e automaticamente uma coluna é escolhida como chave primária. Por default a opção WITH PRIMARY KEY é usada. Também pode ser usada a opção WITH ROWID para ser gerado um campo contendo o ID individual. Maiores detalhes podem ser encontrados na documentação oficial da Oracle neste link.

Após a criação da visão materializada, outros indices podem ser criados.

Postgres

As visões materializadas no PostgreSQL usam as mesmas regras que as visões simples, mas persistem os resultados em forma de tabela. O procedimento de criação é muito simples:

CREATE MATERIALIZED VIEW IF NOT EXISTS view-name
AS
SELECT ...

A partir de agora, já podemos criar indices para a visão. Infelizmente, o Postgres não faz a atualização automática dos dados. A maneira mais simples para fazer isso é executar manualmente ou via Job o comando abaixo:

REFRESH MATERIALIZE VIEW view-name;

Atualizando a visão concorrentemente

Este tipo é util quando não se deseja incomodar o usuário com bloqueios ocasionados no momento da atualização. Entretanto, para isso ser possivel, deve ser criado um índice unico na visão. Ele irá ajudar na identificação das linhas livres. Exemplo de atualização dos dados:

CREATE UNIQUE INDEX index-name ON view-name(column_id);

REFRESH MATERIALIZE VIEW CONCURRENTLY view-name;

Esta forma de atualização não é a mais rapida, porém não incomodará seus usuários.

Criando Job

Como foi citado anteriormente o uso de Job para acionar a atualização, precisamos deixar bem claro que o Postgres não dispõe deste recurso. Devemos fazer o uso de recurso do Sistema Operacional:

  • CRON (Linux)
  • Windows Tasks Scheduler (Windows)

O exemplo a seguir demonstra o que deverá ser executado pelo CRON do Linux:

$ psql -d meu_banco -u nome_usuario -f "meu_script.sql" 

Conclusões

O SQLServer traz algumas dificuldades a mais para se criar a visão indexada. Porém, realiza o trabalho de atualização dos dados automaticamete.

No Oracle, a criação é muito simples e oferece opções quanto a forma de atualização dos dados.

Em relação ao Postgres, a criação também é simples, mas não oferece mecanismo de atualização automática. E este é o grande diferencial do Postgres, quanto aos demais.

De qualquer forma, todos os três SGBDs oferecem o recurso de visão materializada e ainda permitem que indices sejam criados para otimizar as buscas. Infelizmente, não temos um padrão ou similaridade nas formas de criação deste tipo de visão.

Boa sorte a todos. Espero ter ajudado.

Referências

https://docs.microsoft.com/pt-br/sql/relational-databases/views/create-indexed-views?view=sql-server-ver15
https://oracle-base.com/articles/misc/materialized-views
https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_6002.htm#SQLRF01302
https://medium.com/jobteaser-dev-team/materialized-views-with-postgresql-for-beginners-9809483db35f
https://www.postgresql.org/docs/10/rules-materializedviews.html
https://www.postgresqltutorial.com/psql-commands/