Suponha que eu tenha uma tabela com muitas colunas com as quais não me importo, mas duas com as quais me importo: Primary
e Secondary
. Há uma chave primária agrupada em Primary
.
CREATE TABLE [dbo].[OnlyTwoGoodColumnsButManyBad]
(
[Primary] INT PRIMARY KEY CLUSTERED,
[Secondary] NVARCHAR(500) NOT NULL,
[Evil1] NVARCHAR(MAX),
[Evil2] NVARCHAR(MAX),
[Evil3] NVARCHAR(MAX),
[Evil4] NVARCHAR(MAX),
[Evil5] NVARCHAR(MAX)
);
Como não me importo com nenhuma das outras colunas, decido que quero este índice:
CREATE NONCLUSTERED INDEX [IX_Primary_Secondary]
ON [dbo].[OnlyTwoGoodColumnsButManyBad]
(
[Primary],
[Secondary]
);
Dado que a lista de chaves deste índice contém a chave primária, não há dúvidas de que a lista de chaves é única. Assim, estou tentado a torná-la UNIQUE
.
CREATE UNIQUE NONCLUSTERED INDEX [UIX_Primary_Secondary]
ON [dbo].[OnlyTwoGoodColumnsButManyBad]
(
[Primary],
[Secondary]
);
Mas isso tem algum benefício? E o que dizer do mesmo caso exato, mas com o Secondary
como a chave de índice principal seguido por Primary
?
Singularidade e Desempenho
Argumentos PARA declarar unicidade
Normalmente, é melhor fornecer mais informações ao otimizador do que menos. Se você sabe que um índice é único, é melhor declará-lo dessa forma. Isso pode ajudar o otimizador, bem como fornecer clareza sobre seus dados para pessoas reais que estão olhando para as definições de esquema.
Isso pode ter um impacto direto no desempenho. Veja o artigo de Paul White Enforcing Uniqueness for Performance para um exemplo.
Argumentos CONTRA a declaração de unicidade
Quanto às especificidades desta questão, tentei adaptar seu cenário de índice não clusterizado à demonstração no artigo de Paul, e parece que buscas singleton são usadas, independentemente de o índice não clusterizado ser declarado exclusivo ou não. Incluí o código de demonstração modificado no final desta resposta.
Com base nisso, parece que o otimizador é capaz de inferir exclusividade pela inclusão da chave UNIQUE do índice clusterizado. Esse conceito é mais completamente confirmado e desenvolvido neste Q&A: Devo marcar um índice composto como exclusivo se ele contiver a chave primária?
Há também certos cenários em que um índice UNIQUE pode causar sobrecarga de desempenho, então não há uma resposta mágica aqui, infelizmente. Veja estes artigos para leitura relacionada:
Ordem das Chaves de Índice
Em relação à ordenação das colunas, isso realmente depende dos tipos de consultas que serão executadas contra essa tabela. E essa é mais ou menos a orientação "geral" sobre índices que entra em jogo aqui. Você geralmente quer a coluna "mais seletiva" primeiro.
Se as consultas normalmente incluem um valor para "Primário" como um filtro (ou condição de junção), então esse é um candidato ideal - você pode buscar diretamente na linha certa. Se as consultas normalmente fornecem apenas um valor para "Secundário", então Primário não é uma boa chave de índice líder - você teria que escanear cada linha na tabela. Nesse caso, Secundário é uma escolha melhor para liderar o índice.
Código de demonstração
Veja abaixo o código que usei. Novamente, ele foi adaptado (possivelmente incorretamente, já que sou apenas um humilde desenvolvedor web) do artigo de Paul:
Há outro benefício em declarar o índice como único.
Cada um
non unique index
é sempre maior que o similarunique index
. Isso ocorre porque no caso de índice não clusterizado não exclusivo, o rowID(RID ou chave de índice clusterizado) também é armazenado em níveis de índice não folha .O índice não clusterizado não exclusivo (seu caso) sempre tem o
clustered index key
presente em todos os níveis de índice, enquanto um índice exclusivo similar não precisa dele em seus níveis não-folha, então quanto maior for sua chave de índice clusterizado, maior será o tamanho do seunon unique
índice não clusterizado.Não consegui encontrar a documentação oficial, mas aqui está uma explicação sobre isso: Por que os níveis raiz e intermediário de índices NÃO exclusivos e NÃO agrupados armazenam adicionalmente o ID da linha?
Ok, aqui está minha reprodução:
Acabei de criar uma tabela a partir da minha tabela de trabalho dbo.Nums que contém números inteiros de 1 a 1000000, coloquei a coluna única n como ela está na coluna n da minha nova tabela e criei outra coluna
replicate('0', 200) + cast(n as varchar(10)) as n1
, aqui a replicação é usada apenas para o propósito de uma coluna grande o suficiente para obter não apenas raiz + folha, mas também 1 nível intermediário.O índice nesta coluna não é único, mas o conteúdo é único por definição.
Então obtenho minhas páginas de índice com DBCC IND:
Pego 2 páginas que representam o nível intermediário e raiz e as examino:
nível intermediário
nível raiz
Ambos têm a coluna de índice clusterizado na como parte da chave. Os valores na coluna n1 são únicos, no entanto.