Muito boa pergunta, pois é um conceito tão importante. Este é um tópico importante e o que vou mostrar é uma simplificação para que você possa entender os conceitos básicos.
Em primeiro lugar, quando você vê a tabela de índice de cluster . No SQL server, se uma tabela não contém um índice em cluster, é uma pilha. Criar um índice em cluster na tabela na verdade transforma a tabela em uma estrutura do tipo b-tree. Seu índice clusterizado É sua tabela, não está separado da tabela
Você já se perguntou por que você pode ter apenas um índice em cluster? Bem, se tivéssemos dois índices agrupados, precisaríamos de duas cópias da tabela. Afinal, ele contém os dados.
Vou tentar explicar isso usando um exemplo simples.
NOTA: Criei a tabela neste exemplo e a preenchi com mais de 3 milhões de entradas aleatórias. Em seguida, executou as consultas reais e colou os planos de execução aqui.
O que você realmente precisa entender é notação O ou eficiência operacional . Vamos supor que você tenha a tabela a seguir.
CREATE TABLE [dbo].[Customer](
[CustomerID] [int] IDENTITY(1,1) NOT NULL,
[CustomerName] [varchar](100) NOT NULL,
[CustomerSurname] [varchar](100) NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED
(
[CustomerID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF
, IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Portanto, aqui temos uma tabela básica com uma chave agrupada no Código do Cliente (a chave primária é agrupada por padrão). Assim, a tabela é organizada / ordenada com base na chave primária CustomerID. Os níveis intermediários conterão os valores CustomerID. As páginas de dados conterão a linha inteira, portanto, é a linha da tabela.
Também criaremos um índice não agrupado no campo CustomerName. O código a seguir fará isso.
CREATE NONCLUSTERED INDEX [ix_Customer_CustomerName] ON [dbo].[Customer]
(
[CustomerName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF
, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF
, DROP_EXISTING = OFF, ONLINE = OFF
, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Portanto, neste índice, você encontrará nas páginas de dados / nós no nível da folha um ponteiro para os níveis intermediários no índice em cluster. O índice é organizado / ordenado em torno do campo CustomerName. Portanto, o nível intermediário contém os valores CustomerName e o nível da folha conterá o ponteiro (esses valores de ponteiro são, na verdade, os valores da chave primária ou a coluna CustomerID).
Certo, se executarmos a seguinte consulta:
SELECT * FROM Customer WHERE CustomerID = 1
O SQL provavelmente lerá o índice em cluster por meio de uma operação de busca. Uma operação de busca é uma pesquisa binária que é muito mais eficiente do que uma varredura que é uma pesquisa seqüencial. Portanto, no exemplo acima, o índice é lido e, usando uma pesquisa binária, o SQL pode eliminar os dados que não correspondem aos critérios que estamos procurando. Veja a captura de tela anexada para o plano de consulta.
Portanto, o número de operações ou Notação O para a operação de busca é o seguinte:
- Faça uma pesquisa binária no índice clusterizado comparando o valor pesquisado com os valores no nível intermediário.
- Retorne os valores correspondentes (lembre-se de que o índice clusterizado possui todos os dados, pode retornar todas as colunas do índice, pois são os dados da linha)
Então são duas operações. No entanto, se executarmos a seguinte consulta:
SELECT * FROM Customer WHERE CustomerName ='John'
O SQL agora usará o índice não clusterizado no CustomerName para fazer a pesquisa. No entanto, como esse é um índice sem cluster, ele não contém todos os dados na linha.
Portanto, o SQL fará a pesquisa nos níveis intermediários para encontrar os registros correspondentes e faça uma pesquisa usando os valores retornados para fazer outra pesquisa no índice clusterizado (também conhecido como tabela) para recuperar os dados reais. Isso parece confuso, eu sei, mas continue a ler e tudo ficará claro.
Como nosso índice não agrupado em cluster contém apenas o campo CustomerName (os valores do campo indexado armazenados nos nós intermediários) e o ponteiro para os dados que são o CustomerID, o índice não possui registro do CustomerSurname. O CustomerSurname deve ser buscado no índice ou tabela em cluster.
Ao executar esta consulta, recebo o seguinte plano de execução:
Há duas coisas importantes para você notar na captura de tela acima
- O SQL está dizendo que tenho um índice ausente (o texto em verde). O SQL está sugerindo que eu crie um índice em CustomerName que inclua CustomerID e CustomerSurname.
- Você também verá que 99% do tempo da consulta é gasto em uma pesquisa de chave no índice de chave primária / índice em cluster.
Por que o SQL está sugerindo o índice no CustomerName novamente? Bem, já que o índice contém apenas o CustomerID e o CustomerName SQL ainda precisa encontrar o CustomerSurname na tabela / índices agrupados.
Se criamos o índice e incluímos a coluna CustomerSurname no índice, o SQL poderá satisfazer a consulta inteira apenas lendo o índice não agrupado em cluster. É por isso que o SQL está sugerindo que eu mude meu índice não agrupado em cluster.
Aqui você pode ver a operação extra que o SQL precisa fazer para obter a coluna CustomerSurname da chave em cluster
Assim, o número de operações é o seguinte:
- Faça pesquisa binária no índice não em cluster comparando o valor pesquisado com os valores no nível intermediário
- Para nós que correspondem, leia o nó no nível da folha que conterá o ponteiro para os dados no índice em cluster (os nós no nível da folha conterão os valores da chave primária a propósito).
- Para cada valor retornado, faça uma leitura no índice clusterizado (a tabela) para obter os valores da linha aqui, leríamos o CustomerSurname.
- Retornar linhas correspondentes
São 4 operações para obter os valores. O dobro da quantidade de operações necessárias em comparação com a leitura do índice em cluster. O programa mostra que seu índice clusterizado é o índice mais poderoso, pois contém todos os dados.
Então, apenas para esclarecer um último ponto. Por que digo que o ponteiro no índice não agrupado é o valor da chave primária? Bem, para demonstrar que os nós no nível folha do índice não clusterizado contêm o valor da chave primária, altero minha consulta para:
SELECT CustomerID
FROM Customer
WHERE CustomerName='Jane'
Nesta consulta, o SQL pode ler o Código do Cliente no índice não clusterizado. Não é necessário fazer uma pesquisa no índice clusterizado. Isso você pode ver pelo plano de execução que se parece com isso.
Observe a diferença entre esta consulta e a consulta anterior. Não há pesquisa. SQL pode encontrar todos os dados no índice não agrupado em cluster
Esperamos que você possa começar a entender que o índice clusterizado é a tabela e os índices não clusterizados NÃO contêm todos os dados. A indexação acelerará as seleções devido ao fato de que pesquisas binárias podem ser feitas, mas apenas índices agrupados contêm todos os dados. Portanto, uma pesquisa em um índice não clusterizado quase sempre resultará no carregamento de valores do índice clusterizado. Essas operações extras tornam os índices não agrupados em cluster menos eficientes que um índice agrupado.
Espero que isso esclareça as coisas. Se algo não fizer sentido, poste um comentário e tentarei esclarecer. É bastante tarde aqui e meu cérebro está um pouco tenso. Hora de um touro vermelho.