Clustered vs Non-Clustered

98

Meu conhecimento de nível inferior de SQL (Server 2008) é limitado e agora está sendo desafiado por nossos DBAs. Deixe-me explicar (mencionei afirmações óbvias na esperança de estar certo, mas se você vir algo errado, diga-me) o cenário:

Temos uma mesa que contém 'Ordens Judiciais' para as pessoas. Quando criei a tabela, (Nome: CourtOrder), criei assim:

CREATE TABLE dbo.CourtOrder
(
  CourtOrderID INT NOT NULL IDENTITY(1,1), (Primary Key)
  PersonId INT NOT NULL,
  + around 20 other fields of different types.
)

Em seguida, apliquei um índice não agrupado à chave primária (para eficiência). Meu motivo é que é um campo único (chave primária), e deve ser indexado, principalmente para fins de seleção, como costumamosSelect from table where primary key = ...

Em seguida, apliquei um índice CLUSTERED em PersonId. O motivo era agrupar pedidos para uma determinada pessoa fisicamente, já que a grande maioria do trabalho é receber pedidos para uma pessoa. Assim,select from mytable where personId = ...

Eu fui questionado sobre isso agora. Disseram-me que devemos colocar o índice clusterizado na chave primária e o índice normal no personId. Isso me parece muito estranho. Em primeiro lugar, por que você colocaria um índice clusterizado em uma coluna exclusiva? o que é agrupamento? Certamente isso é um desperdício do índice clusterizado? Eu teria acreditado que um índice normal seria usado em uma coluna única. Além disso, agrupar o índice significaria que não podemos agrupar uma coluna diferente (uma por tabela, certo?).

O motivo pelo qual me disseram que cometi um erro é que eles acreditam que colocar um índice clusterizado no PersonId tornaria as inserções lentas. Para o ganho de 5% na velocidade de uma seleção, estaríamos obtendo uma degradação de 95% na velocidade de inserções e atualizações. Isso é correto e válido?

Eles dizem que, como agrupamos o personId, o SQL Server precisa reorganizar os dados sempre que inserimos ou fazemos uma alteração no PersonId.

Então eu perguntei, por que o SQL teria o conceito de CLUSTERED INDEX, se é tão lento? É tão lento quanto eles estão dizendo? Como devo configurar meus índices para obter um desempenho ideal? Eu teria pensado que SELECT é usado mais do que INSERT ... mas eles dizem que estamos tendo problemas de bloqueio em INSERTS ...

Espero que alguém possa me ajudar.

Craig
fonte

Respostas:

117

A distinção entre um índice clusterizado e um índice não clusterizado é que o índice clusterizado determina a ordem física das linhas no banco de dados . Em outras palavras, aplicar o índice clusterizado a PersonIdsignifica que as linhas serão fisicamente classificadas por PersonIdna tabela, permitindo que uma pesquisa de índice vá direto para a linha (em vez de um índice não clusterizado, que o direcionaria para a linha localização, adicionando uma etapa extra).

Dito isso, é incomum que a chave primária não seja o índice clusterizado, mas não é algo inédito. O problema com seu cenário é, na verdade, o oposto do que você está assumindo: você deseja valores exclusivos em um índice clusterizado, não duplicatas. Como o índice clusterizado determina a ordem física da linha, se o índice estiver em uma coluna não exclusiva, o servidor deve adicionar um valor de plano de fundo às linhas que têm um valor de chave duplicado (no seu caso, quaisquer linhas com o mesmo PersonId) para que o valor combinado (chave + valor de plano de fundo) seja único.

A única coisa que eu sugeriria não é usar uma CourtOrderIdcoluna de surrogate key (your ) como a chave primária, mas em vez disso, usar uma chave primária composta de PersonIde alguma outra coluna de identificação exclusiva ou conjunto de colunas. Se isso não for possível (ou prático), coloque o índice clusterizado ativado CourtOrderId.

Adam Robinson
fonte
Obrigado Adam. Então, quando um índice clusterizado seria útil? Achei que a vantagem do índice clusterizado era agrupar os dados, para momentos em que, por exemplo, a maioria das consultas está em um PersonID ... então os dados seriam agrupados.
Craig
3
É não fisicamente Weaver PersonId. É classificado logicamente por PersonId, qualquer discrepância entre a ordem lógica e física é o grau de fragmentação lógica.
Martin Smith
1
@cdotlister O benefício de um índice é classificar os dados, não agrupá-los (o que implica dados duplicados dentro do índice). Embora a distinção possa parecer semântica, no caso de índices agrupados não é. Se possível, o índice clusterizado deve estar em algo que identifique exclusivamente a linha e (de preferência) também seja a coluna ou conjunto de colunas mais consultado. É por isso que geralmente está na chave primária.
Adam Robinson
1
@CyberSluethOmega: Não sei; sua pergunta não contém informações suficientes para eu tomar uma decisão. Eu gostaria de um índice clusterizado em um conjunto de colunas onde as linhas seriam frequentemente adicionadas ou excluídas, exceto no final da tabela ? Não. Mas eu não tenho certeza do porque você está perguntando isso ou porque o voto negativo.
Adam Robinson
1
@CyberSluethOmega: A Internet pode fazer com que os comentários pareçam defensivos ou frios quando não foram feitos dessa forma. Você alegou que eu disse que não sabia de nenhuma circunstância em que tornar o índice clusterizado algo diferente da chave primária, quando na verdade eu não disse tal coisa. Na verdade, o que eu disse foi "este é incomum ..., mas não impossível", o que significa que eu não sei de casos em que isso é feito.
Adam Robinson
14

Não sou de forma alguma um especialista em SQL ... então considere isso como uma visão de desenvolvedor, em vez de uma visão de DBA.

Inserções em índices agrupados (fisicamente ordenados) que não estão em ordem sequencial causam trabalho extra para inserções / atualizações. Além disso, se você tiver muitas inserções acontecendo ao mesmo tempo e todas elas ocorrerem no mesmo local, você terá contenção. Seu desempenho específico varia de acordo com seus dados e como você os acessa. A regra geral é construir seu índice de cluster no valor estreito mais exclusivo de sua tabela (normalmente o PK)

Estou assumindo que seu PersonId não será alterado, portanto, as atualizações não entram em jogo aqui. Mas considere um instantâneo de algumas linhas com PersonId de 1 2 3 3 4 5 6 7 8 8

Agora insira 20 novas linhas para PersonId de 3. Primeiro, uma vez que esta não é uma chave única, o servidor adiciona alguns bytes extras ao seu valor (nos bastidores) para torná-lo único (o que também adiciona espaço extra) e, em seguida, o local onde estes vão residir tem que ser alterado. Compare isso com a inserção de um PK de incremento automático onde as inserções acontecem no final. A explicação não técnica provavelmente se resumiria a isto: há menos trabalho de 'embaralhar as folhas' a fazer se estiver progredindo naturalmente com valores mais altos no final da tabela em vez de retrabalhar a localização dos itens existentes naquele local ao inserir seus itens.

Agora, se você está tendo problemas com Inserts, então provavelmente está inserindo um monte de valores PersonId iguais (ou semelhantes) de uma vez, o que está causando esse trabalho extra em vários lugares da tabela e a fragmentação está matando você. A desvantagem de alternar para o PK em cluster no seu caso, é se você está tendo problemas de inserção hoje em PersonIds que variam em valores espalhados pela tabela, se você alternar seu índice de cluster para o PK e todas as inserções agora acontecerem em um localização, então seu problema pode realmente piorar devido ao aumento da concentração de contenção. (Por outro lado, se suas inserções hoje não estão espalhadas por todo o lado, mas são normalmente agrupadas em áreas semelhantes, então o seu problema provavelmente será facilitado mudando seu índice agrupado de PersonId para seu PK, porque você estará minimizando o fragmentação.)

Seus problemas de desempenho devem ser analisados ​​de acordo com sua situação específica e considerar esses tipos de respostas apenas como diretrizes gerais. Sua melhor aposta é confiar em um DBA que possa validar exatamente onde estão seus problemas. Parece que você tem problemas de contenção de recursos que podem estar além de um simples ajuste de índice. Isso pode ser um sintoma de um problema muito maior. (Prováveis ​​problemas de design ... caso contrário, limitações de recursos.)

De qualquer forma, boa sorte!

Darian Miller
fonte
5

Alguns autores sugerem não "desperdiçar" o CIem uma identitycoluna se houver uma alternativa que beneficiaria as consultas de intervalo.

A partir das Diretrizes de design de índices agrupados do MSDN, a chave deve ser escolhida de acordo com os seguintes critérios

  1. Pode ser usado para consultas usadas com frequência.
  2. Fornece um alto grau de exclusividade.
  3. Pode ser usado em consultas de intervalo.

Sua CourtOrderIDcoluna se encontra 2. Seus PersonIdencontros 1e 3. Como a maioria das linhas acabará com a uniqueifieradição de qualquer maneira, você também pode declará-la como única e usar, PersonId,CourtOrderIDpois terá a mesma largura, mas será mais útil porque a chave do índice clusterizado é adicionada a todos os NCIs como o localizador de linha e isso permitirá para cobrir mais consultas.

O principal problema em usar PersonId,CourtOrderIDcomo o IC é que provavelmente ocorrerá fragmentação lógica (e isso afeta particularmente as consultas de intervalo que você está tentando ajudar), portanto, você precisaria monitorar o fator de preenchimento e os níveis de fragmentação e realizar a manutenção do índice com mais frequência.

Martin Smith
fonte
3

É explicado no seguinte link: https://msdn.microsoft.com/en-us/ms190457.aspx

Aglomerado

  • Os índices agrupados classificam e armazenam as linhas de dados na tabela ou exibição com base em seus valores-chave. Estas são as colunas incluídas na definição do índice. Pode haver apenas um índice clusterizado por tabela, porque as próprias linhas de dados podem ser classificadas em apenas uma ordem.

  • A única vez em que as linhas de dados em uma tabela são armazenadas em ordem de classificação é quando a tabela contém um índice clusterizado. Quando uma tabela tem um índice clusterizado, a tabela é chamada de tabela clusterizada. Se uma tabela não tiver um índice clusterizado, suas linhas de dados serão armazenadas em uma estrutura não ordenada chamada heap.

Não clusterizado

  • Os índices não clusterizados têm uma estrutura separada das linhas de dados. Um índice não clusterizado contém os valores-chave do índice não clusterizado e cada entrada de valor-chave tem um ponteiro para a linha de dados que contém o valor-chave .

  • O ponteiro de uma linha de índice em um índice não clusterizado para uma linha de dados é chamado de localizador de linha. A estrutura do localizador de linha depende se as páginas de dados são armazenadas em um heap ou em uma tabela agrupada. Para um heap, um localizador de linha é um ponteiro para a linha. Para uma tabela clusterizada, o localizador de linha é a chave do índice clusterizado.

  • Você pode adicionar colunas não chave ao nível folha do índice não clusterizado para contornar os limites de chave de índice existentes, 900 bytes e 16 colunas chave, e executar consultas totalmente cobertas e indexadas.

user2191454
fonte
-3

Algum banco de dados com algumas seleções desagradáveis, junta-se a um procedimento armazenado - apenas a diferença é o índice

INDEXES - agrupado vs não agrupado

  891 rows
  10 sec
  NONCLUSTERED 

  OR

  891 rows
  14 sec
  CLUSTERED
toLucky
fonte