Visualizações e Índices

Visualizações e Índices

Imagine que você pega livros frequentemente na biblioteca. Existem duas maneiras de encontrar um livro: a primeira é procurar em todas as prateleiras toda vez (varredura completa da tabela); a segunda é verificar primeiro o catálogo de índice e ir diretamente à prateleira correta (consulta por índice). A "lista de leitura recomendada" da biblioteca é como uma visualização — não é uma prateleira real, mas uma lista curada de livros de diferentes prateleiras, facilitando encontrar o que você quer. Visualizações e índices no SQL funcionam da mesma forma.


1. Conceitos Fundamentais

Visualização — Conceito

Uma visualização é uma tabela virtual que não armazena dados, mas salva uma instrução SELECT. Cada vez que você acessa a visualização, o banco de dados executa a consulta definida da visualização e retorna os resultados.

SQL
-- Criar uma visualização: visualização de informações de funcionários
CREATE VIEW v_employee_info AS
SELECT 
    e.employee_id,
    CONCAT(e.first_name, e.last_name) AS nome,
    e.salary,
    d.department_name AS departamento,
    d.city
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id;

Usar uma visualização é igual a usar uma tabela regular:

SQL
-- Consultar a visualização
SELECT * FROM v_employee_info WHERE salary > 10000;

Criando Visualizações

SQL
CREATE VIEW nome_visualizacao AS
SELECT instrucao;
SQL
-- Criar uma visualização de estatísticas de departamento
CREATE VIEW v_department_stats AS
SELECT 
    d.department_id,
    d.department_name AS departamento,
    COUNT(e.employee_id) AS qtd_funcionarios,
    AVG(e.salary) AS salario_medio,
    SUM(e.salary) AS salario_total
FROM departments d
LEFT JOIN employees e ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name;

Modificando Visualizações

SQL
-- Método 1: CREATE OR REPLACE (recomendado)
CREATE OR REPLACE VIEW v_employee_info AS
SELECT 
    e.employee_id,
    CONCAT(e.first_name, e.last_name) AS nome,
    e.salary,
    e.hire_date,
    d.department_name AS departamento
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id;

-- Método 2: ALTER VIEW
ALTER VIEW v_employee_info AS
SELECT employee_id, first_name, last_name, salary FROM employees;

Excluindo Visualizações

SQL
DROP VIEW IF EXISTS v_employee_info;
💡 Dica: Excluir uma visualização não afeta os dados da tabela subjacente — uma visualização é apenas um "atalho" para uma consulta.

Vantagens das Visualizações

Vantagem Descrição
Simplificar consultas complexas Encapsula JOINs complexos como visualizações; use com apenas SELECT * FROM nome_visualizacao
Segurança de dados Expõe apenas certas colunas ou linhas aos usuários, ocultando dados sensíveis
Independência lógica Modificar definições de visualização não afeta aplicações que usam a visualização
Lógica consistente Garante que todos os usuários usem a mesma lógica de consulta, evitando escrita repetida

Desvantagens das Visualizações

Desvantagem Descrição
Sobrecarga de desempenho Cada acesso requer executar a consulta subjacente; visualizações complexas podem ser lentas
Limitações de atualização Visualizações contendo JOINs, funções de agregação ou DISTINCT geralmente não são atualizáveis
Dificuldade de depuração Visualizações aninhadas em múltiplas camadas aumentam a dificuldade de solução de problemas
💡 Dica: Visualizações não armazenam dados por si mesmas — são "aliases de consulta". Quando os dados da tabela subjacente mudam, os resultados da visualização mudam correspondentemente.


Índice — Conceito

Um índice é uma estrutura de dados, semelhante ao sumário de um livro, que ajuda o banco de dados a localizar rapidamente os dados e evitar varreduras completas da tabela.

SQL
-- Sem índice: varredura completa da tabela (buscar linha por linha)
SELECT * FROM employees WHERE last_name = 'Zhang';

-- Com índice: busca direta (via índice)
CREATE INDEX idx_last_name ON employees(last_name);
SELECT * FROM employees WHERE last_name = 'Zhang';

Criando Índices

SQL
-- Índice regular (permite valores duplicados)
CREATE INDEX idx_coluna ON nome_tabela(nome_coluna);

-- Índice único (não permite valores duplicados)
CREATE UNIQUE INDEX idx_coluna ON nome_tabela(nome_coluna);

-- Índice fulltext (para busca de texto completo)
CREATE FULLTEXT INDEX idx_coluna ON nome_tabela(nome_coluna);

-- Índice composto (combinação multi-coluna)
CREATE INDEX idx_colunas ON nome_tabela(coluna1, coluna2);

Excluindo Índices

SQL
-- Sintaxe MySQL
DROP INDEX idx_coluna ON nome_tabela;

-- Sintaxe padrão
ALTER TABLE nome_tabela DROP INDEX idx_coluna;

Tipos de Índice

Tipo Palavra-chave Descrição Caso de Uso
Índice Regular INDEX Índice básico, permite valores duplicados Colunas consultadas frequentemente
Índice Único UNIQUE INDEX Valores da coluna devem ser únicos E-mail, números de RG, etc.
Índice Fulltext FULLTEXT INDEX Suporta busca de texto completo Conteúdo de artigos, descrições de produtos
Índice Composto INDEX(col1, col2) Índice de combinação multi-coluna Consultas com múltiplas condições

Índice Composto e Regra do Prefixo Mais à Esquerda

Índices compostos seguem a regra do prefixo mais à esquerda: condições de consulta devem corresponder da coluna mais à esquerda do índice para utilizá-lo.

SQL
-- Criar um índice composto
CREATE INDEX idx_name_age ON employees(last_name, first_name, salary);

-- ✅ Pode usar o índice (corresponde à coluna mais à esquerda)
SELECT * FROM employees WHERE last_name = 'Zhang';
SELECT * FROM employees WHERE last_name = 'Zhang' AND first_name = 'Wei';

-- ❌ Não pode usar o índice (pula a coluna mais à esquerda)
SELECT * FROM employees WHERE first_name = 'Wei';
SELECT * FROM employees WHERE salary > 10000;
💡 Dica: Ao projetar índices compostos, coloque as colunas mais usadas nas consultas à esquerda.

Custo dos Índices

Custo Descrição
Espaço de armazenamento Índices requerem espaço adicional em disco
Desempenho de escrita INSERT/UPDATE/DELETE precisam sincronizar atualizações de índice
Custo de manutenção Muitos índices reduzem a velocidade de escrita
💡 Dica: Mais não é melhor! Crie índices apenas para colunas que são consultadas frequentemente e possuem grandes volumes de dados. Tabelas pequenas (algumas centenas de linhas) geralmente não precisam de índices.


2. Sintaxe Básica

Sintaxe de Visualização

SQL
-- Criar uma visualização
CREATE [OR REPLACE] VIEW nome_visualizacao AS SELECT instrucao;

-- Consultar uma visualização (igual a uma tabela regular)
SELECT * FROM nome_visualizacao WHERE condicao;

-- Excluir uma visualização
DROP VIEW [IF EXISTS] nome_visualizacao;
💡 Dica: Recomenda-se nomear visualizações com prefixo v_ ou view_ para facilmente distingui-las de tabelas reais.

Sintaxe de Índice

SQL
-- Criar um índice
CREATE [UNIQUE|FULLTEXT] INDEX nome_indice ON nome_tabela(coluna1, coluna2, ...);

-- Excluir um índice
DROP INDEX nome_indice ON nome_tabela;

-- Visualizar índices de uma tabela
SHOW INDEX FROM nome_tabela;
💡 Dica: Chaves primárias (PRIMARY KEY) e restrições de unicidade (UNIQUE) criam índices automaticamente — não é necessário criar manualmente.

💡 Dica: Use EXPLAIN para verificar se uma consulta usa um índice: EXPLAIN SELECT * FROM employees WHERE last_name = 'Zhang';


Exemplo: Criando e Usando Visualizações (Dificuldade ⭐)

SQL
-- Criar uma visualização de detalhes do pedido
CREATE OR REPLACE VIEW v_order_detail AS
SELECT 
    o.order_id,
    CONCAT(e.first_name, e.last_name) AS responsavel,
    d.department_name AS departamento,
    o.order_date,
    o.total_amount AS valor,
    o.status
FROM orders o
LEFT JOIN employees e ON o.employee_id = e.employee_id
LEFT JOIN departments d ON e.department_id = d.department_id;

-- Consultar usando a visualização
SELECT * FROM v_order_detail WHERE status = 'completed';
▶ Experimente

Saída:

TEXT
order_id | responsavel | departamento | order_date | valor   | status
---------+-------------+--------------+------------+---------+-----------
    1001 | WangQiang   | Sales        | 2026-05-10 | 2500.00 | completed
    1002 | WangQiang   | Sales        | 2026-05-15 | 1800.00 | completed
    1005 | ZhaoMin     | Sales        | 2026-06-10 | 4100.00 | completed
SQL
-- Usar a visualização para agregar valores de pedidos por departamento
SELECT departamento, COUNT(*) AS qtd_pedidos, SUM(valor) AS valor_total
FROM v_order_detail
GROUP BY departamento;

Abordagem da consulta:

  1. A visualização encapsula a lógica complexa de JOIN de três tabelas
  2. Consultas simples são tudo que é necessário — não é necessário reescrever o JOIN
  3. Os resultados da visualização atualizam automaticamente conforme os dados subjacentes mudam

Exemplo: Criando Índices para Otimizar Desempenho de Consulta (Dificuldade ⭐⭐)

SQL
-- Visualizar o plano de execução da consulta atual
EXPLAIN SELECT * FROM employees WHERE last_name = 'Zhang';
▶ Experimente

Saída (sem índice):

TEXT
+----+-------------+-----------+------+---------------+------+---------+------+------+-------+
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-----------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL |    6 | Using where |
+----+-------------+-----------+------+---------------+------+---------+------+------+-------+

type = ALL indica uma varredura completa da tabela, rows = 6 indica que todas as linhas foram escaneadas.

SQL
-- Criar um índice
CREATE INDEX idx_last_name ON employees(last_name);

-- Visualizar o plano de execução novamente
EXPLAIN SELECT * FROM employees WHERE last_name = 'Zhang';

Saída (com índice):

TEXT
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+-------+
| id | select_type | table     | type | possible_keys | key           | key_len | ref   | rows | Extra |
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+-------+
|  1 | SIMPLE      | employees | ref  | idx_last_name | idx_last_name | 152     | const |    1 |       |
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+-------+

type = ref indica que o índice está sendo usado, rows = 1 indica que apenas 1 linha foi escaneada.

SQL
-- Criar um índice composto
CREATE INDEX idx_status_date ON orders(status, order_date);

-- Consulta que pode usar o índice
EXPLAIN SELECT * FROM orders WHERE status = 'completed' AND order_date > '2026-06-01';

-- Visualizar todos os índices de uma tabela
SHOW INDEX FROM employees;

Abordagem da consulta:

  1. Coluna type do EXPLAIN: ALL (varredura completa) → ref (referência de índice) indica melhoria de desempenho
  2. Coluna rows: menos linhas escaneadas é melhor
  3. Índices compostos devem ser usados seguindo a regra do prefixo mais à esquerda

3. Cenários Comuns de Aplicação

Cenário 1: Simplificar Gerenciamento de Permissões com Visualizações

SQL
-- Criar uma visualização contendo apenas informações não sensíveis
CREATE OR REPLACE VIEW v_employee_public AS
SELECT 
    employee_id,
    CONCAT(first_name, last_name) AS nome,
    d.department_name AS departamento
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id;

-- Usuários comuns só podem acessar esta visualização, não salário ou outras informações sensíveis
SELECT * FROM v_employee_public;
💡 Abordagem: Exclua colunas sensíveis (como salário, e-mail) da visualização e controle o acesso aos dados através da visualização.

Cenário 2: Implementar Relatórios de Dados com Visualizações

SQL
-- Criar uma visualização de relatório de vendas mensal
CREATE OR REPLACE VIEW v_monthly_sales AS
SELECT 
    DATE_FORMAT(order_date, '%Y-%m') AS mes,
    COUNT(*) AS qtd_pedidos,
    SUM(total_amount) AS total_vendas,
    AVG(total_amount) AS valor_medio_pedido,
    COUNT(DISTINCT customer_id) AS qtd_clientes
FROM orders
WHERE status != 'cancelled'
GROUP BY DATE_FORMAT(order_date, '%Y-%m');

-- Consultar o relatório
SELECT * FROM v_monthly_sales ORDER BY mes;

Saída:

TEXT
mes     | qtd_pedidos | total_vendas | valor_medio_pedido | qtd_clientes
--------+-------------+--------------+--------------------+-------------
2026-05 |           2 |      4300.00 |            2150.00 |            2
2026-06 |           3 |      8250.00 |            2750.00 |            3

❓ Perguntas Frequentes

P: Qual a diferença entre uma visualização e uma tabela temporária? R: Visualizações não armazenam dados — cada consulta executa o SQL subjacente, então os resultados estão sempre atualizados; tabelas temporárias armazenam instantâneos de dados, oferecendo consultas mais rápidas mas dados potencialmente desatualizados. Visualizações são adequadas para modelos de consulta de longo prazo, enquanto tabelas temporárias são adequadas para etapas de cálculo intermediário.

P: Visualizações podem modificar dados? R: Depende da definição da visualização. Visualizações contendo JOINs, funções de agregação, DISTINCT ou subconsultas geralmente não são atualizáveis (apenas SELECT). Visualizações simples de tabela única (sem agregação) podem ser atualizadas com UPDATE. Na prática, visualizações são usadas principalmente para consulta — modificar dados através de visualizações não é recomendado.

P: Mais índices são sempre melhores? R: Não. Índices consomem espaço de armazenamento e reduzem o desempenho de INSERT/UPDATE/DELETE. Crie índices apenas para colunas que são consultadas frequentemente e possuem alta cardinalidade (muitos valores distintos). Tabelas pequenas geralmente não precisam de índices.

P: Como posso saber se uma consulta está usando um índice? R: Use o comando EXPLAIN para visualizar o plano de execução. Focando na coluna type: ALL (varredura completa, mais lento) → indexrangerefeq_refconst (mais rápido). Se type for ALL e a tabela tiver uma grande quantidade de dados, um índice pode ser necessário.


📖 Resumo


📝 Exercícios

Exercício 1 (⭐): Crie uma visualização v_high_salary mostrando informações de funcionários (nome, salário, nome do departamento) para funcionários com salário acima de 10000, depois use a visualização para consultar funcionários de alto salário no departamento "Technology".

Exercício 2 (⭐⭐): Crie uma visualização v_department_report contendo nome do departamento, contagem de funcionários, salário médio, maior salário e menor salário. Depois use a visualização para encontrar o departamento com o maior salário médio.

Exercício 3 (⭐⭐): Crie um índice na coluna customer_id da tabela orders, e use EXPLAIN para comparar o desempenho da consulta antes e depois de criar o índice. Depois crie um índice composto em orders(status, order_date) e teste quais consultas podem utilizá-lo.


Próxima Lição

👉 18-practice-aggregate - Prática: Análise de Dados: Aplique funções de agregação, consultas com agrupamento, expressões condicionais e funções avançadas juntas para melhorar suas habilidades de análise de dados através de cenários práticos!

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%