DP-900: entender e usar índices em Azure SQL Database
Vou ensinar a competência de compreender e aplicar índices em Azure SQL Database — um tema chave em "Dados relacionais no Azure" do DP-900. Saber como os índices funcionam importa tanto para responder às perguntas conceptuais do exame como para optimizar consultas na prática. Aqui explico conceitos, dou exemplos concretos e mostro como validar o impacto de um índice no mundo real.
O que precisas de saber
Um índice é uma estrutura que acelera a leitura de dados, semelhante ao índice de um livro que aponta para páginas onde um tema aparece. Em bases de dados relacionais como Azure SQL Database, índices reduzem o número de páginas de disco ou blocos que o sistema tem de ler para satisfazer uma consulta. Em termos práticos, uma consulta que antes fazia 2 000 logical reads pode passar a fazer 20 reads quando um índice adequado é utilizado — uma redução de 99% no trabalho de leitura em alguns cenários.
Exemplo simples: uma tabela Customers(id, name, city). Se escreveres muitas consultas que filtram por city, criar um índice em city pode tornar essas consultas muito mais rápidas porque o motor procura no índice em vez de ler a tabela completa (full table scan). Se a tabela tem 1 milhão de linhas e cada página de disco contém 8 KB, um full scan pode requerer milhares de páginas lidas; um índice selectivo reduz esse número drasticamente.
Conceitos essenciais:
- Clustered index: determina a ordem física das linhas na tabela. Uma tabela pode ter apenas um clustered index (ex.: PRIMARY KEY por defeito). Escolhe uma chave clustered que seja estreita, estável e única sempre que possível (por exemplo, um ID incremental).
- Non-clustered index: estrutura separada que mantém apontadores para as linhas da tabela; podes ter vários por tabela. Podem incluir colunas adicionais (INCLUDE) para criar um covering index.
- Covering index: um índice que contém todas as colunas necessárias para uma consulta, evitando acessos adicionais à tabela. Por exemplo, um índice em (customer_id) INCLUDE (order_date, total) cobre uma query que só retorna essas colunas.
- Seletividade: medida de quão exclusiva é uma coluna. Colunas com alta seletividade (p.ex., > 10% de valores distintos num conjunto grande) beneficiam mais de um índice; colunas com baixa seletividade (p.ex., género com apenas M/F) raramente ajudam.
- Overhead: índices aceleram leitura mas aumentam o custo nas operações de escrita (INSERT/UPDATE/DELETE) e consomem espaço. Como regra prática, cada índice non-clustered pode adicionar 20–50% ao custo de armazenamento dependendo das colunas incluídas.
Como funciona na prática
Aqui tens um passo-a-passo prático para criar e validar um índice em Azure SQL Database usando T-SQL. Supõe que tens uma tabela Sales(order_id INT, customer_id INT, sale_date DATE, amount DECIMAL(10,2)).
-- 1. Criar um non-clustered index na coluna sale_date
CREATE INDEX IX_Sales_SaleDate
ON Sales(sale_date);
-- 2. Ver plano de execução para uma query que filtra por sale_date
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
SELECT order_id, amount
FROM Sales
WHERE sale_date = '2025-01-15';
-- 3. Remover o índice se não for útil
DROP INDEX IX_Sales_SaleDate ON Sales;
Passos a considerar para decidir criar um índice:
- Identificar consultas frequentes e colunas usadas em WHERE, JOIN, ORDER BY. Ferramentas em Azure como Query Performance Insight e Intelligent Insights ajudam a ver queries mais dispendiosas.
- Avaliar seletividade: se uma coluna tem muitos valores repetidos, o índice pode não ser útil. Ex.: se 90% das linhas têm status = 'Active', um índice em status terá pouco efeito.
- Testar com e sem índice usando planos de execução, STATISTICS IO/TIME e medir logical reads. Observa métricas como tempo de CPU e elapsed time; uma melhoria de 10–100x é comum em casos ideais.
- Monitorizar impacto nas escritas: índices aumentam latência de INSERT/UPDATE/DELETE. Em cargas de escrita intensiva, cada índice pode acrescentar 1–5% de overhead por operação, dependendo da complexidade.
Erros comuns
- Indexar todas as colunas: criar demasiados índices (ou índices em colunas pouco seletivas) aumenta o overhead nas escritas e ocupa espaço desnecessário. Em ambientes OLTP, manter 3–6 índices por tabela é comum; >10 costuma ser problemático.
- Ignorar planos de execução: criar índices sem analisar o plano pode não resolver o problema; o Query Optimizer escolhe se usa o índice. Um índice mal desenhado pode sequer ser utilizado.
- Não manter estatísticas: estatísticas desactualizadas levam o Query Optimizer a escolhas subótimas; lembra-te de UPDATE STATISTICS ou de configurar auto_update_statistics. Em tabelas grandes, uma actualização de estatísticas pode melhorar dramaticamente os planos.
- Esquecer manutenção: índices fragmentam-se com o tempo; procedimentos de manutenção (REORGANIZE ou REBUILD) devem ser planeados. Em tabelas activas, um REBUILD semanal ou mensal pode ser necessário, dependendo da fragmentação (p.ex., >30%).
Como praticar
Pratica em Azure SQL Database com uma base de dados de amostra (ex.: WideWorldImporters ou AdventureWorks) e experimenta:
- Criar/descartar índices e comparar planos de execução. Observa logical_reads antes/depois e aponta números concretos (ex.: de 2 500 para 150 reads).
- Medir STATISTICS IO/TIME antes e depois para quantificar ganhos em I/O e tempo de CPU.
- Simular carga de escrita para observar overhead: usa scripts que façam milhares de INSERT/UPDATE para medir latência e throughput com e sem índice.
Nota: Azure SQL Database tem funcionalidades de tuning automático que sugerem e aplicam índices; revê sempre as sugestões e testa antes de aplicar em produção. Para preparares o DP-900 usa o Practice Assessment OFICIAL (gratuito) da Microsoft e a study guide oficial (gratuita). Estes recursos ajudam-te a verificar conhecimentos nas áreas medidas pelo exame sem recorrer a materiais proibidos.
Em resumo
- Índices aceleram leituras; há clustered e non-clustered, cada um com trade-offs.
- Escolhe colunas com alta seletividade e uso frequente em filtros/join/order by. Considera incluir colunas com INCLUDE para criar covering indexes.
- Testa alterações com planos de execução e métricas (STATISTICS IO/TIME) e monitoriza o impacto nas escritas.
- Evita excesso de índices, mantém estatísticas actualizadas e programa manutenção (REORGANIZE/REBUILD) para evitar fragmentação.