⚡ CAPÍTULO 16: VIEWS, ÍNDICES E OTIMIZAÇÃO
Escrever um SQL que devolve o resultado correto é fácil. Escrever um SQL que devolve o resultado correto em 3 milissegundos sob um banco com 10 milhões de linhas é o que separa um programador iniciante de um Arquiteto de Software. 🛡️🧩
🎯 Objetivo Curricular
Aprender a abstrair a complexidade e aumentar a segurança com a criação de VIEWs. Entender o impacto arquitetural da criação de Índices na leitura vs gravação e analisar planos de execução com o comando EXPLAIN.
🏢 O Cenário Prático (Seu Desafio)
Na TecProExpress, a tabela de Pacotes atingiu 5 milhões de registros. A busca no painel do usuário ("Procurar pacote pelo Código de Rastreio") começou a demorar 8 segundos para responder. Os clientes estão reclamando no Reclame Aqui. Além disso, o RH pediu um relatório com os dados dos estagiários, mas o banco se recusou a dar acesso à tabela original, pois nela constam salários confidenciais.
"Seu desafio é criar uma
VIEWcega para proteger os salários do RH e implementar umÍndice(Index) no Código de Rastreio para derrubar o tempo de busca da tabela de pacotes de 8 segundos para 3 milissegundos!"
🧠 Fundamentos 1: O Encapsulamento (VIEW)
Uma VIEW (Visão) é uma tabela virtual. Ela não armazena dados físicos no HD. Ela armazena apenas a "lógica" de um SELECT.
- Segurança: Você pode criar uma VIEW que esconde a coluna "Salario" da tabela original e dar permissão para o usuário ler apenas essa VIEW.
- Abstração: Se você tem um relatório que exige 5
JOINssuper complexos, você pode salvar tudo isso em umaVIEW. O desenvolvedor frontend apenas faráSELECT * FROM nome_da_view;.
🛠️ Criando a Visão do RH
-- DDL Rápido: A tabela original (Intocável)
-- CREATE TABLE funcionario (id INT, nome VARCHAR(50), salario DECIMAL(10,2));
-- Criando a Visão Segura (Ignoramos o salário de propósito)
CREATE VIEW vw_funcionarios_rh AS
SELECT id, nome FROM funcionario;
-- Como o usuário (RH) irá consultar:
SELECT * FROM vw_funcionarios_rh;
🧠 Fundamentos 2: O Acelerador (Índices)
Quando você manda o SGBD procurar o código de rastreio 'BR123', e a tabela não tem Índice, o banco faz um Full Table Scan (Ele lê a linha 1, depois a linha 2... até a linha 5.000.000). Isso é terrível.
Um Índice (Index) é uma cópia organizada de uma coluna específica, guardada em uma árvore de busca (B-Tree). Funciona como o índice remissivo no final de um livro.
📊 Comparação de Busca
flowchart LR
A["Tabela sem Índice<br/>(Lê 5 milhões de linhas)"] -->|O(N)| B["Demora 8 segundos"]
C["Tabela com Índice B-Tree<br/>(Busca binária)"] -->|O(log N)| D["Demora 3 milissegundos"]
⚠️ O Preço do Índice
Se índices são tão maravilhosos, por que não colocamos em TODAS as colunas?
Porque o Índice atrasa a gravação. Toda vez que houver um INSERT ou UPDATE, o banco terá que escrever o dado na tabela e depois reorganizar a árvore do Índice.
A Regra: Tabelas com muita leitura (Consultas) exigem índices. Tabelas com muita gravação (ex: Logs de GPS em tempo real) exigem o mínimo de índices possível.
📖 Exemplo Guiado: Otimizando o Rastreio (EXPLAIN)
O comando EXPLAIN é a ferramenta de raio-x do SGBD. Ele não executa a consulta, ele te diz o "Plano Matemático" que o SGBD faria.
🛠️ Código do Exemplo
-- DDL Base
-- CREATE TABLE pacote_log (id INT, codigo_rastreio VARCHAR(15), status VARCHAR(20));
-- (Imagine 5 milhões de inserts aqui)
-- 1. O Diagnóstico: "Como você faria essa busca, Banco de Dados?"
EXPLAIN SELECT * FROM pacote_log WHERE codigo_rastreio = 'BR123';
-- O SGBD responderá: type = "ALL" (Ele vai ler TODAS as linhas).
-- 2. A Cura (DDL de Otimização)
CREATE INDEX idx_pacote_rastreio ON pacote_log(codigo_rastreio);
-- 3. O Novo Diagnóstico
EXPLAIN SELECT * FROM pacote_log WHERE codigo_rastreio = 'BR123';
-- O SGBD responderá: type = "ref" (Usando o Índice). Velocidade máxima atingida!
🛠️ Prática Obrigatória: Abstração e Velocidade
Cenário: O sistema de relatórios da TecProExpress.
- Crie a tabela
faturamentocomid_venda,data_venda,nome_clienteevalor_lucro. - Crie uma
VIEWchamadavw_vendas_publicasque mostre apenas a data e o cliente (escondendo o lucro da equipe de vendas). - Crie um
INDEXna colunadata_vendapara acelerar os relatórios de fechamento mensal.
🚀 Script de Seed (Gabarito de Otimização)
-- 1. Tabela Original (DDL)
CREATE TABLE faturamento (
id_venda INT PRIMARY KEY,
data_venda DATE,
nome_cliente VARCHAR(100),
valor_lucro DECIMAL(15,2)
);
-- 2. View Segura (DQL encapsulada em DDL)
CREATE VIEW vw_vendas_publicas AS
SELECT data_venda, nome_cliente
FROM faturamento;
-- 3. Índice Estratégico (DDL)
CREATE INDEX idx_data_fechamento ON faturamento(data_venda);
📤 Instruções de Entrega (Microsoft Teams)
Após validar seus códigos práticos e de estudo:
Use o operador e para critérios rigorosos e ou para critérios flexíveis. Salve os arquivos com a extensão .sql (Ex: Atividade_XX_SeuNome.sql ou Atividade_XX_SeuNome.png ou Atividade_XX_SeuNome.drawio
💡 Checkpoint de Lógica
[!TIP] Dica do Engenheiro: Um erro clássico de performance é colocar o código dentro de funções (ex:
WHERE YEAR(data_venda) = 2026). Quando você envolve a coluna com uma função, o SGBD é forçado a ignorar o Índice e fazer o Full Table Scan. O correto para alta velocidade é:WHERE data_venda BETWEEN '2026-01-01' AND '2026-12-31'. 🧠🛡️