Índices no SQL Server: como funcionam e quando criá-los

Índices no SQL Server: como funcionam e quando criá-los
Publicado em 26/10/2026 por Admin

O desempenho de uma aplicação que utiliza SQL Server depende, em grande medida, da forma como os dados são consultados, armazenados e atualizados.

À medida que as tabelas crescem, consultas que inicialmente respondiam em poucos milissegundos podem começar a demorar mais tempo. Uma operação que percorre algumas centenas de registos pode tornar-se dispendiosa quando precisa de analisar milhões de linhas.

Uma das ferramentas mais importantes para enfrentar este problema são os índices.

Os índices permitem que o SQL Server localize e organize os dados de forma eficiente, reduzindo o trabalho necessário para executar determinadas consultas. No entanto, criar índices sem compreender o seu funcionamento pode produzir o efeito contrário: aumentar o consumo de armazenamento, tornar as operações de escrita mais lentas e introduzir custos desnecessários de manutenção.

Neste artigo, vamos explorar como funcionam os índices no SQL Server, quais são os principais tipos, quando faz sentido criá-los e como avaliar se estão realmente a melhorar o desempenho.

1. O que é um índice no SQL Server?

Um índice é uma estrutura de dados que ajuda o SQL Server a localizar registos sem precisar de examinar toda a tabela em determinadas situações.

Uma forma simples de compreender o conceito é imaginar o índice remissivo de um livro.

Sem um índice, para encontrar todas as referências a um determinado assunto, seria necessário percorrer as páginas do início ao fim.

Com um índice remissivo, é possível localizar o assunto e consultar as páginas correspondentes diretamente.

No SQL Server, o princípio é semelhante: um índice mantém informações organizadas sobre determinadas colunas, permitindo ao mecanismo de base de dados encontrar os registos relevantes de forma mais eficiente.

Nos índices tradicionais baseados em linhas, a estrutura utiliza uma árvore B+ para organizar as chaves e facilitar a pesquisa.

Contudo, é importante compreender que o índice não é gratuito. A sua criação exige espaço de armazenamento e a sua manutenção pode aumentar o custo de operações como INSERT, UPDATE e DELETE.

O objetivo não é criar o maior número possível de índices, mas encontrar um conjunto adequado às consultas e às operações de escrita da aplicação.

2. Como funciona um índice na prática?

Imagine uma tabela de clientes com milhões de registos:

CREATE TABLE Customers
(
    Id INT IDENTITY(1,1) PRIMARY KEY,
    Name NVARCHAR(150) NOT NULL,
    Email NVARCHAR(200) NOT NULL,
    City NVARCHAR(100) NULL
);

Considere agora a seguinte consulta:

SELECT Id, Name, Email
FROM Customers
WHERE Email = 'cliente@example.com';

Se não existir um índice adequado para Email, o SQL Server poderá ter de examinar uma grande parte da tabela para encontrar o registo pretendido.

A operação exata depende do plano de execução escolhido, da estrutura da tabela e das características dos dados.

Podemos criar um índice não clusterizado sobre a coluna Email:

CREATE INDEX IX_Customers_Email
ON Customers (Email);

Este índice organiza as chaves de Email e mantém referências às linhas correspondentes.

Quando o otimizador considera que o índice é uma boa opção, o SQL Server pode utilizá-lo para localizar mais rapidamente os registos associados ao valor procurado.

Esta abordagem pode reduzir significativamente as leituras necessárias, sobretudo quando a consulta seleciona uma pequena parte dos registos existentes.

No entanto, a melhoria não é garantida em todos os cenários. Se a consulta precisar de devolver uma grande percentagem da tabela, o otimizador poderá considerar mais eficiente utilizar outra estratégia.

A decisão final depende do plano de execução e das características da carga de trabalho.

3. Índice clustered: o que é e como funciona?

O índice clusterizado, ou clustered index, define a organização das páginas de dados de uma tabela baseada em linhas.

Numa tabela com um índice clusterizado, as páginas de dados encontram-se organizadas segundo a chave desse índice. A estrutura da árvore B+ contém os próprios dados nos seus níveis folha.

Uma tabela pode ter apenas um índice clusterizado, porque os dados não podem estar organizados simultaneamente segundo duas estruturas clusterizadas diferentes.

Quando uma tabela é criada com uma chave primária, o SQL Server normalmente cria um índice para garantir a respetiva unicidade. Esse índice pode ser clusterizado ou não clusterizado, dependendo da definição e dos índices existentes.

Por exemplo:

CREATE TABLE Orders
(
    Id INT IDENTITY(1,1) NOT NULL,
    CustomerId INT NOT NULL,
    OrderDate DATETIME2 NOT NULL,
    Total DECIMAL(18,2) NOT NULL,

    CONSTRAINT PK_Orders
        PRIMARY KEY CLUSTERED (Id)
);

Neste exemplo, a chave primária é explicitamente definida como clusterizada.

Esta opção pode ser adequada quando a chave é utilizada frequentemente para localizar registos e quando a organização dos dados segundo essa chave é apropriada para a carga de trabalho.

Quando utilizar um índice clusterizado?

A escolha deve considerar:

  • Os padrões de pesquisa mais frequentes.

  • As operações de ordenação e intervalo.

  • O tamanho e a estabilidade da chave.

  • A frequência das inserções e atualizações.

  • O impacto da chave nos restantes índices.

Uma chave clusterizada larga aumenta o espaço necessário para armazenar a referência à chave nos índices não clusterizados.

Uma chave com valores que exigem inserções em posições intermédias também pode introduzir custos de manutenção, dependendo do padrão de escrita e da configuração do índice.

Por isso, uma chave clusterizada deve ser escolhida com base no comportamento esperado da tabela, e não apenas porque uma determinada coluna é a chave primária.

4. Índice nonclustered: quando utilizar?

O índice não clusterizado, ou nonclustered index, é uma estrutura separada da organização principal dos dados da tabela.

Armazena as chaves das colunas indexadas e informações que permitem localizar as linhas correspondentes.

Uma tabela pode ter vários índices não clusterizados, desde que o seu custo de armazenamento e manutenção seja justificado pelos benefícios obtidos.

Por exemplo, numa tabela de encomendas, podemos pesquisar frequentemente por cliente:

SELECT Id, OrderDate, Total
FROM Orders
WHERE CustomerId = 100;

Um índice adequado pode ajudar o SQL Server a localizar as encomendas desse cliente sem percorrer toda a tabela.

A sua criação seria:

CREATE INDEX IX_Orders_CustomerId
ON Orders (CustomerId);

Este índice é especialmente interessante quando a tabela possui muitos registos e a consulta procura apenas uma parte deles.

Ainda assim, a eficácia depende da distribuição dos valores, do número de registos devolvidos e do custo de obter as restantes colunas.

Se a consulta precisar de recuperar dados adicionais que não estão no índice, o SQL Server poderá ter de aceder à estrutura de dados da tabela.

Em determinados cenários, esse acesso adicional pode representar uma parte importante do custo da consulta.

5. Índices compostos: quando indexar várias colunas?

Um índice composto utiliza mais do que uma coluna como chave.

É particularmente útil quando as consultas filtram ou ordenam os dados através de uma combinação de campos.

Imagine uma aplicação que pesquisa frequentemente as encomendas de um cliente num determinado intervalo de datas:

SELECT Id, OrderDate, Total
FROM Orders
WHERE CustomerId = 100
  AND OrderDate >= '2026-01-01'
  AND OrderDate < '2027-01-01';

Podemos considerar um índice composto:

CREATE INDEX IX_Orders_CustomerId_OrderDate
ON Orders (CustomerId, OrderDate);

Neste caso, CustomerId é a primeira coluna da chave e OrderDate é a segunda.

A ordem é importante porque influencia a forma como o índice pode ser utilizado.

Com esta definição, o SQL Server pode procurar primeiro o cliente e, dentro do conjunto correspondente, localizar as encomendas no intervalo de datas.

O mesmo índice também pode ser útil para determinadas consultas que filtram apenas por CustomerId.

Por outro lado, não é necessariamente a melhor escolha para uma consulta que filtra apenas por OrderDate, porque essa coluna não é a primeira chave do índice.

Isto não significa que um índice composto só possa ser utilizado quando todas as colunas estão presentes na consulta. Significa que a ordem das chaves condiciona as pesquisas que a estrutura consegue suportar de forma eficiente.

Como escolher a ordem das colunas?

Não existe uma regra universal que determine a ordem ideal para todas as situações.

A escolha deve considerar:

  • Os predicados utilizados nas consultas.

  • A seletividade das colunas.

  • Os intervalos de pesquisa.

  • As condições de igualdade e desigualdade.

  • As operações de ordenação.

  • A reutilização do índice por outras consultas.

Uma boa abordagem consiste em analisar as consultas mais relevantes e testar diferentes definições com dados representativos.

Criar um índice composto com muitas colunas apenas para tentar cobrir todas as consultas pode aumentar desnecessariamente o armazenamento e o custo de manutenção.

6. Índices com INCLUDE: como evitar acessos adicionais à tabela?

Por vezes, uma consulta utiliza uma coluna para filtrar os registos, mas precisa de devolver outras colunas que não fazem parte da chave do índice.

Considere:

SELECT Id, OrderDate, Total
FROM Orders
WHERE CustomerId = 100;

Podemos definir um índice com uma coluna-chave e colunas incluídas:

CREATE INDEX IX_Orders_CustomerId
ON Orders (CustomerId)
INCLUDE (OrderDate, Total);

A coluna CustomerId faz parte da chave do índice. Já OrderDate e Total são armazenadas como colunas incluídas, sem integrarem a chave de pesquisa.

Se o índice contiver todas as colunas necessárias para satisfazer a consulta, o SQL Server poderá executá-la diretamente a partir do índice.

Quando isso acontece, dizemos que o índice cobre a consulta.

Um índice de cobertura pode evitar acessos adicionais à tabela e melhorar o desempenho de determinadas operações de leitura.

Contudo, incluir muitas colunas aumenta o tamanho do índice e o custo das operações que o mantêm atualizado.

Por isso, a utilização de INCLUDE deve ser orientada pelas consultas que realmente justificam essa otimização.

7. Índices únicos: como garantir a unicidade dos dados?

Um índice único impede que existam chaves duplicadas segundo as regras de unicidade aplicáveis ao índice.

Por exemplo, se a aplicação exige que cada endereço de email seja único:

CREATE UNIQUE INDEX UX_Customers_Email
ON Customers (Email);

Esta definição garante que não existem valores duplicados para a chave Email.

É importante compreender que um índice único não serve apenas para melhorar o desempenho. Também permite impor uma regra de integridade diretamente no banco de dados.

No entanto, antes de criar o índice numa tabela existente, é necessário verificar se já existem duplicados. Caso contrário, a criação poderá falhar.

Também deve considerar o comportamento de valores nulos e as regras específicas do SQL Server para índices únicos, de acordo com as colunas e a definição utilizada.

Quando a unicidade faz parte das regras de negócio, garanti-la na base de dados é geralmente mais robusto do que depender exclusivamente de uma validação prévia na aplicação.

Uma verificação feita apenas em C# pode não ser suficiente para impedir duplicados quando duas operações concorrentes tentam inserir o mesmo valor.

8. Índices filtrados: quando indexar apenas parte da tabela?

Um índice filtrado é um índice não clusterizado que contém apenas as linhas que satisfazem uma condição específica.

É útil quando determinadas consultas trabalham repetidamente com um subconjunto dos dados.

Imagine uma tabela de encomendas que contém encomendas pendentes, processadas e canceladas.

Se a aplicação consulta frequentemente apenas as encomendas pendentes, pode fazer sentido avaliar um índice filtrado:

CREATE INDEX IX_Orders_Pending
ON Orders (OrderDate)
INCLUDE (CustomerId, Total)
WHERE Status = 1;

Neste exemplo, assume-se que Status = 1 representa uma encomenda pendente.

O índice contém apenas as linhas que satisfazem essa condição, reduzindo potencialmente o espaço necessário em comparação com um índice equivalente que inclua todos os estados.

Também pode diminuir o custo de manutenção em operações que afetam apenas registos fora do filtro.

Contudo, a consulta precisa de apresentar condições compatíveis com o filtro para que o otimizador possa utilizar o índice de forma adequada.

Antes de adotar esta estratégia, verifique se o subconjunto é suficientemente relevante, se a consulta beneficia da estrutura e se o comportamento dos dados justifica a manutenção de um índice específico.

9. Quando devemos criar um índice?

A decisão de criar um índice deve partir de uma necessidade observada.

Alguns cenários justificam uma investigação mais aprofundada:

Consultas frequentes com filtros seletivos

Se uma aplicação procura repetidamente registos por uma coluna, e cada consulta devolve apenas uma pequena parte da tabela, um índice nessa coluna pode reduzir significativamente o trabalho necessário.

Exemplos incluem pesquisas por identificador externo, número de encomenda ou endereço de email.

Joins frequentes entre tabelas

Quando duas tabelas são frequentemente relacionadas através de uma coluna, pode ser útil avaliar se a coluna utilizada na junção possui um índice adequado.

O benefício depende da consulta, da cardinalidade e do plano de execução. Nem todos os joins exigem índices adicionais.

Consultas com ordenação ou intervalos

Consultas que utilizam ORDER BY, condições de intervalo ou combinações de filtros podem beneficiar de índices cujas chaves correspondam aos padrões de acesso mais relevantes.

A ordem das colunas é especialmente importante nestes cenários.

Problemas confirmados no plano de execução

Se o plano de execução mostrar leituras dispendiosas e a análise indicar que um índice adequado poderia reduzir o volume de dados examinado, a criação de um índice torna-se uma hipótese a testar.

O SQL Server também pode apresentar recomendações de índices em determinados planos de execução. Essas recomendações são úteis como ponto de partida, mas não devem ser aplicadas cegamente.

É necessário verificar se o índice proposto se sobrepõe a estruturas existentes e qual será o impacto sobre o conjunto da carga de trabalho.

10. Quando não devemos criar um índice?

Criar um índice para todas as colunas utilizadas nas consultas é uma estratégia inadequada.

Os índices têm custos e nem todos os campos justificam uma estrutura adicional.

Tabelas pequenas

Uma tabela com poucos registos pode ser consultada eficientemente através de uma leitura direta.

Nesse caso, o custo de utilizar um índice pode ser superior ao benefício obtido.

Colunas com pouca seletividade

Uma coluna com poucos valores distintos pode não beneficiar de um índice isolado para determinadas consultas.

Por exemplo, uma coluna que contém apenas os estados Ativo e Inativo pode não ser suficientemente seletiva quando a maioria dos registos pertence ao mesmo estado.

No entanto, um índice sobre essa coluna pode ser útil se existir um filtro apropriado, se a distribuição dos dados o justificar ou se fizer parte de um índice composto.

A seletividade deve ser analisada em conjunto com o padrão de consulta.

Tabelas com muitas operações de escrita

Cada índice adicional pode aumentar o custo das inserções, atualizações e eliminações.

Quando uma tabela recebe grandes volumes de escrita, a manutenção de múltiplos índices pode representar uma parte significativa do trabalho executado pelo SQL Server.

Índices redundantes

Dois índices com chaves e colunas incluídas semelhantes podem sobrepor-se parcialmente.

Antes de criar um novo índice, verifique se uma estrutura existente já suporta a consulta ou se pode ser ajustada para satisfazer mais do que um padrão de acesso.

O objetivo deve ser manter um conjunto de índices útil, e não acumular estruturas que raramente são utilizadas.

11. Como avaliar o impacto de um índice

Depois de criar um índice, é necessário verificar se a alteração trouxe os benefícios esperados.

Uma abordagem prática consiste em estabelecer uma linha de base antes da alteração e repetir os testes depois da criação.

Compare o plano de execução

Verifique se o SQL Server passou a utilizar o índice e se houve alterações relevantes nas operações executadas.

Analise as linhas estimadas e reais, os acessos à tabela e a quantidade de dados processados.

Não considere a utilização do índice uma prova suficiente de melhoria. Um índice pode ser utilizado e, ainda assim, produzir um plano pouco eficiente.

Analise as leituras lógicas

Pode utilizar SET STATISTICS IO ON para observar as leituras realizadas por uma consulta.

Por exemplo:

SET STATISTICS IO ON;
SET STATISTICS TIME ON;

SELECT Id, OrderDate, Total
FROM Orders
WHERE CustomerId = 100;

SET STATISTICS TIME OFF;
SET STATISTICS IO OFF;

Compare os resultados antes e depois da alteração, utilizando condições de teste equivalentes.

Uma redução das leituras lógicas pode indicar que a consulta passou a examinar menos páginas de dados.

Observe o impacto sobre as operações de escrita

Um índice pode melhorar uma consulta de leitura e aumentar o custo de inserções ou atualizações.

Por isso, a validação deve considerar a carga de trabalho como um todo, especialmente em tabelas com elevada atividade de escrita.

Utilize o Query Store

O Query Store permite acompanhar o desempenho das consultas ao longo do tempo e identificar alterações no comportamento dos planos.

Esta ferramenta é útil para verificar se a melhoria se mantém durante a utilização normal da aplicação e se a criação do índice teve efeitos indesejados noutras consultas.

12. Como descobrir índices pouco utilizados?

O SQL Server disponibiliza vistas de gestão dinâmica que ajudam a analisar a utilização dos índices.

Por exemplo:

SELECT
    OBJECT_SCHEMA_NAME(i.object_id) AS SchemaName,
    OBJECT_NAME(i.object_id) AS TableName,
    i.name AS IndexName,
    COALESCE(s.user_seeks, 0) AS UserSeeks,
    COALESCE(s.user_scans, 0) AS UserScans,
    COALESCE(s.user_lookups, 0) AS UserLookups,
    COALESCE(s.user_updates, 0) AS UserUpdates
FROM sys.indexes AS i
LEFT JOIN sys.dm_db_index_usage_stats AS s
    ON s.object_id = i.object_id
    AND s.index_id = i.index_id
    AND s.database_id = DB_ID()
WHERE i.object_id > 0
ORDER BY
    COALESCE(s.user_updates, 0) DESC;

Esta consulta apresenta informações sobre a utilização dos índices da base de dados atual, incluindo pesquisas, leituras e atualizações registadas.

É importante interpretar estes dados com cuidado.

As estatísticas de utilização não constituem um histórico permanente e podem ser reiniciadas, por exemplo, quando o serviço SQL Server é reiniciado.

Além disso, um índice que parece pouco utilizado durante um período de observação pode ser importante para um processo mensal, uma operação de manutenção ou uma consulta crítica executada apenas em determinadas circunstâncias.

Antes de remover um índice, confirme a duração do período de observação, os requisitos da aplicação, as dependências e o comportamento da carga de trabalho.

A remoção de índices deve ser uma decisão fundamentada, acompanhada de validação e de um plano de reversão adequado.

13. Boas práticas para gerir índices no SQL Server

Para manter um conjunto de índices eficiente, considere as seguintes recomendações:

  • Analise as consultas reais antes de criar índices.

  • Utilize os planos de execução para identificar operações dispendiosas.

  • Considere a seletividade das colunas e a distribuição dos dados.

  • Escolha cuidadosamente a ordem das chaves nos índices compostos.

  • Utilize INCLUDE apenas quando existir um benefício justificável.

  • Evite criar índices redundantes.

  • Avalie os custos sobre as operações de escrita.

  • Monitorize a utilização dos índices ao longo do tempo.

  • Utilize o Query Store para acompanhar alterações no desempenho.

  • Teste as alterações com dados e cargas representativos.

  • Considere os custos de armazenamento e manutenção.

  • Documente o motivo da criação de índices importantes.

Também é fundamental compreender que a manutenção de índices não se resume a reconstruí-los periodicamente.

A reorganização ou reconstrução de um índice pode ser útil em determinadas circunstâncias, mas deve ser orientada pelo estado da estrutura, pela carga de trabalho e pelos objetivos de manutenção.

Fragmentação, isoladamente, não é uma razão suficiente para aplicar indiscriminadamente operações de manutenção a todos os índices.

Conclusão

Os índices são uma ferramenta essencial para otimizar o desempenho de aplicações que utilizam SQL Server.

Quando bem concebidos, podem reduzir as leituras necessárias, acelerar pesquisas e melhorar o tempo de resposta das operações mais importantes.

No entanto, cada índice representa um compromisso entre o desempenho das consultas, o custo das operações de escrita, o espaço de armazenamento e a complexidade da manutenção.

Por isso, a melhor estratégia não consiste em criar índices para todas as colunas, mas em identificar os padrões de acesso relevantes, analisar os planos de execução e testar alterações com base em métricas concretas.

Para os programadores .NET, compreender os índices é particularmente importante porque permite estabelecer uma ligação entre o código da aplicação, o SQL gerado pelo Entity Framework Core ou executado através do Dapper e o comportamento real do banco de dados.

A regra fundamental é simples: crie índices para resolver problemas identificados, valide os resultados e acompanhe o impacto ao longo do tempo.

Uma estratégia de indexação bem fundamentada contribui para aplicações mais rápidas, bases de dados mais eficientes e uma utilização mais equilibrada dos recursos de infraestrutura.