Quando uma chave primária deve ser declarada sem cluster?

169

Ao criar um banco de dados de teste para outra pergunta que fiz anteriormente, lembrei-me de que uma Chave Primária podia ser declarada NONCLUSTERED

Quando você usaria uma NONCLUSTEREDchave primária em oposição a uma CLUSTEREDchave primária?

desde já, obrigado

Stuart Blackler
fonte

Respostas:

188

A questão não é 'quando o PK deve ser NC', mas, em vez disso, você deve perguntar 'qual é a chave apropriada para o índice em cluster'?

E a resposta realmente depende de como você consulta os dados . O índice clusterizado tem uma vantagem sobre todos os outros índices: como sempre inclui todas as colunas, está sempre cobrindo. Portanto, as consultas que podem alavancar o índice clusterizado certamente não precisam usar pesquisas para satisfazer algumas das colunas e / ou predicados projetados.

Outra peça do quebra-cabeça é como um índice pode ser usado ? Existem três padrões típicos:

  • análises, quando um único valor-chave é procurado no índice
  • varreduras de intervalo, quando um intervalo de valores-chave é recuperado
  • ordem por requisitos, quando um índice pode satisfazer uma ordem sem requerer uma classificação de interrupção

Portanto, se você analisar sua carga esperada (as consultas) e descobrir que um grande número de consultas usaria um índice específico porque elas usam um certo padrão de acesso que se beneficia de um índice, faz sentido propor esse índice como o índice clusterizado.

Ainda outro fator é que a chave de índice em cluster é a chave de pesquisa usada por todos os índices não em cluster e, portanto, uma chave de índice em cluster amplo cria um efeito cascata e amplia todos os índices não em cluster e os índices amplos significam mais páginas, mais E / S , mais memória, menos bondade.

Um bom índice de cluster é estável , não muda durante a vida útil da entidade, porque uma alteração nos valores da chave de índice em cluster significa que a linha deve ser excluída e inserida novamente.

E um bom índice de cluster cresce em ordem não aleatória (cada valor de chave recém-inserido é maior que o valor anterior) para evitar divisões e fragmentação de página (sem mexer com FILLFACTORs).

Portanto, agora que sabemos o que é uma boa chave de índice em cluster, a chave primária (que é uma propriedade lógica da modelagem de dados) corresponde aos requisitos? Se sim, o PK deve ser agrupado. Se não, o PK deve estar sem cluster.

Para dar um exemplo, considere uma tabela de fatos de vendas. Cada entrada possui um ID que é a chave primária. Mas a grande maioria das consultas solicita dados entre uma data e outra data; portanto, a melhor chave de índice em cluster seria a data de vendas , não o ID . Outro exemplo de ter um índice de cluster diferente da chave primária é uma chave de seletividade muito baixa, como uma 'categoria' ou um 'estado', uma chave com apenas muito poucos valores distintos. Ter uma chave de índice em cluster com essa chave de baixa seletividade como a chave mais à esquerda, por exemplo (state, id), geralmente faz sentido devido às varreduras de intervalos que procuram todas as entradas em um determinado 'estado'.

Uma última observação sobre a possibilidade de uma chave primária não agrupada em cluster sobre uma pilha (ou seja, não há nenhum índice agrupado). Pode ser um cenário válido, o motivo típico é quando o desempenho da inserção em massa é crítico, pois os heaps têm uma taxa de transferência de inserção em massa significativamente melhor quando comparados aos índices em cluster.

Remus Rusanu
fonte
1
O que "ordem por requisitos, quando um índice pode satisfazer uma ordem sem necessidade de uma ordem de parar e ir", significa aqui?
Mike Sherrill 'Cat Recall'
2
@RemusRusanu. +1 resposta muito útil. Uma pergunta sobre o exemplo (state, id). Neste exemplo, o requisito "bom índice clusterizado cresce em ordem não aleatória" não será atendido, não é? Então, podemos considerá-lo um bom índice de cluster?
LCJ 09/09
26

O motivo básico para usar índices agrupados é declarado na Wikipedia :

O armazenamento em cluster altera o bloco de dados em uma determinada ordem distinta para corresponder ao índice, resultando nos dados da linha sendo armazenados em ordem. Portanto, apenas um índice em cluster pode ser criado em uma determinada tabela de banco de dados. Os índices clusterizados podem aumentar bastante a velocidade geral de recuperação, mas geralmente apenas onde os dados são acessados ​​sequencialmente na mesma ordem ou ordem inversa do índice clusterizado ou quando um intervalo de itens é selecionado.

Digamos que eu tenha uma tabela de Pessoas e essas pessoas tenham uma coluna País e uma Chave Primária exclusiva. É uma tabela demográfica, portanto, essas são as únicas coisas que me interessam; qual país e quantas pessoas únicas estão vinculadas a esse país.

Assim, só tenho probabilidade de selecionar WHERE ou ORDER BY a coluna Country; um índice agrupado na Chave Primária não me serve de nada, não estou acessando esses dados pelo PK, estou acessando-os por essa outra coluna. Como só posso ter um índice em cluster em uma tabela, declarar minha PK como em cluster me impediria de usar um índice em cluster no país.

Além disso, aqui está um bom artigo sobre Índices em cluster versus não clusterizado: os índices em cluster causaram problemas de desempenho de inserção no SQL Server 6.5 (que, pelo menos, espero que não seja relevante para a maioria de nós aqui).

Se você colocar um índice em cluster em uma coluna IDENTITY, todas as suas inserções acontecerão na última página da tabela - e essa página ficará bloqueada durante o período de cada IDENTITY. Não é grande coisa ... a menos que você tenha 5.000 pessoas que desejam a última página. Então você tem muita disputa para essa página

Observe que esse não é o caso em versões posteriores.

Ben Brocka
fonte
3
FIY, você mencionou o SQL Server 6.5: dba.stackexchange.com/questions/1584/…
gbn
15

Se a sua chave primária for do tipo UNIQUEIDENTIFIER, especifique que é NONCLUSTERED. Se você o agrupar, cada inserção precisará fazer uma série de embaralhamento de registros para inserir a nova linha na posição correta. Isso vai prejudicar o desempenho.

Bryan Johns
fonte
1
Enquanto tento evitar UUIDs para chaves em cluster, acredito que o raciocínio acima pode estar incompleto. O servidor SQL não reorganiza necessariamente as linhas para inserir um na posição correta (se você quer dizer "entre o valor mais alto e o mais baixo"). Considere uma inserção no meio de uma tabela de trilhões de linhas. Indirecionamento extra é necessidade, que pode ser o que você quis dizer. Um UNIQUEIDENTIFIERtipo seqüencial também existe e tem a mesma probabilidade de gerar chaves exclusivas, embora ainda sofra de um tamanho 128.
Charles Burns
8

Um exemplo muito comum:

  • Customermesa com CustomerIDcomoCLUSTERED PRIMARY KEY
  • Tabela de pedidos com OrderID (PK), CustomerID, OrderDatee algumas outras colunas
  • OrderPositions com OrderPositionID (PK), OrderId, ProductID, Amount, Price ...
  • você precisa indexar as tabelas de pedidos

É claro que "depende" é - como quase sempre - a resposta correta, mas a maioria dos aplicativos (não os BI-Reports) funcionará com base no cliente (por exemplo, você faz o login como cliente 278 no site e clica em "Meus pedidos" ou o funcionário lista todos os pedidos do cliente 4569 ou sua rotina de fatura resumirá todos os pedidos do cliente 137).

Nesse caso, não faria muito sentido agrupar a tabela pelo OrderID. Sim, você terá perguntas SELECT ... WHERE OrderId = ?para listar os detalhes do pedido, mas isso geralmente é curto e barato (três leituras).

Por outro lado, se você agrupasse sua Ordertabela pelo CustomerID, não seria necessário fazer várias pesquisas de chave toda vez que você consultar a tabela CustomerId = ?.

A CLUSTERED INDEXdeve ser sempre UNIQUE, caso contrário, SQL Server acrescentaria um (= inutilizável) coluna INT invisível UNIQUIFIERpara garantir a uniquiness - e faria muito mais sentido para adicionar dados reais (utilizável), em seguida, algumas coisas aleatórias (dependendo da ordem de inserção).

Como um cliente (esperançosamente) fará mais de um pedido, teríamos de adicionar o OrderID(ou se você costuma fazer isso) o OrderDate(se for um período de data - caso contrário, o cliente estaria limitado a um pedido por dia) para o CLUSTERED INDEXe acabar com:

CREATE UNIQUE CLUSTERED INDEX IX_Orders_UQ on Orders (CustomerID, OrderID)

As mesmas regras se aplicam à OrderPositionstabela. Normalmente, a maioria das consultas irá listar todas as posições para a ordem específica, então você deve criar o PK com o OrderPositionIDcomo NONCLUSTEREDe uma UNIQUE CLUSTERED INDEXno OrderId, OrderPositionID.

BTW: é correto que a Customertabela seja agrupada por sua PK (a CustomerID, porque é uma "tabela de nível superior" e, em um aplicativo típico, será consultada principalmente por seu CustomerID.

Tabelas de pesquisa pura como por exemplo, Gendersou InvoiceTypesou PaymentTypesão outro exemplo de tabelas que devem ser agrupados por sua PK (porque normalmente você vai se juntar a eles em GenderId, InvoiceTypeIdou PaymentTypeId).

Thomas Franz
fonte
2

Quando um índice em cluster é considerado mais benéfico para o sistema geral do que uma PK em cluster usando alguma medida de desempenho. Só pode haver um índice em cluster em uma tabela.

Exemplos de medidas de desempenho são o tempo de consulta única (velocidade), a integração do tempo total de consulta com a tabela (eficiência) e a necessidade de adicionar muitas colunas de inclusão a um índice não clusterizado muito grande para obter desempenho semelhante ao clusterizado (tamanho )

Isso pode acontecer quando os dados geralmente são recuperados usando um índice que não é exclusivo, contém nulos (não permitidos em uma PK) ou a PK foi adicionada por um motivo secundário (como replicação ou identificação do registro da trilha de auditoria).

crokusek
fonte