Seleção de Índice em Cluster - PK ou FK?

11

Eu tenho uma tabela do SQL Server 2014 que se parece com o seguinte:

OrderId     int           not null IDENTITY --this is the primary key column
OrderDate   datetime2     not null
CustomerId  int           not null
Description nvarchar(255) null

Algumas pessoas da minha equipe sugeriram que o índice clusterizado deveria estar ativado OrderId, mas acho que o CustomerId+ OrderIdseria uma opção melhor pelos seguintes motivos:

  • Quase todas as consultas serão visualizadas WHERE CustomerId = @param, nãoOrderId
  • CustomerIdé uma chave estrangeira para a Customertabela, portanto, ter um índice clusterizado com CustomerIddeve acelerar as junções
  • Embora CustomerIdnão seja exclusivo, ter a OrderIdcoluna adicional especificada no índice garantirá a exclusividade (podemos usar a UNIQUEpalavra - chave ao criar o índice clusterizado nessas duas colunas, para evitar a sobrecarga de não ter exclusividade)
  • Depois que os dados são inseridos, CustomerIde OrderIdnunca mudam, para que essas linhas não se movam após a gravação inicial.
  • O acesso aos dados acontece por meio de um ORM que solicita todas as colunas por padrão; portanto, quando uma consulta baseada em CustomerIdchega, o índice clusterizado poderá fornecer todas as colunas sem nenhum trabalho adicional.

A abordagem CustomerIde OrderIdparece a melhor opção, considerando o exposto acima? Ou, OrderIdpor si só , é melhor, já que é uma coluna única que garante a exclusividade por si só?

Atualmente, a tabela possui um índice clusterizado OrderIde um índice não clusterizado CustomerId, mas não está cobrindo, portanto, como estamos usando um ORM e todas as colunas são solicitadas, é trabalho extra recuperá-las. Portanto, neste post, estou tentando considerar melhorar o desempenho com um IC melhor.

A atividade em nosso banco de dados é de cerca de 85% de leituras e 15% de gravações.

Andy
fonte

Respostas:

5

Resposta do wiki da comunidade :

Eu acho que uma chave de índice clusterizada composta com CustomerID como a primeira coluna será a melhor, já que está na WHEREcláusula de quase todas as consultas.

Pode haver mais divisões em comparação com uma chave incremental (ou uma densidade de página subótima mais provável por um tempo, se você gerenciar e manter o fator de preenchimento para evitar divisões 'ruins'). No entanto, a melhoria geral do desempenho para consultas de clientes é substancial, porque a pesquisa principal é evitada.

OrderID ou OrderDate pode ser melhor para a segunda coluna, dependendo das suas consultas mais críticas.

Por exemplo, se os clientes virem uma lista cronológica de pedidos recentes após fazer login em um site, o OrderDate deverá ser o próximo a otimizar ORDER BY OrderDate DESC.

Se você escolher CódigoDoPedido como o índice agrupado, com um índice não agrupado no Código do Cliente , você ainda terá divisões e fragmentação, apenas no índice não agrupado.

user126897
fonte
3

Se esta tabela exigir muita gravação (por exemplo, muitas mais INSERTdeclarações estão ocorrendo do que SELECTdeclarações contra ela), eu discordo da resposta da wiki .

Escolher CustomerID como a primeira coluna de uma chave agrupada composta gerará muitas divisões no meio da página . Esperamos que você tenha muitos clientes existentes e também muitos novos o tempo todo. Como os clientes (esperançosamente) estão fazendo vários pedidos à medida que sua empresa continua a crescer, essa abordagem exibirá uma boa quantidade de divisões no meio da página que reduzirão o desempenho não apenas nas gravações, mas também serão lidas, pois seus índices ficarão fortemente fragmentados e provavelmente contém quantidades maiores de espaço em branco (o que significa perda de armazenamento e memória).

Se você achar que CustomerID deve ser a coluna principal de um índice clusterizado composto, poderá reduzir o impacto das divisões da página intermediária ajustando FILLFACTORtodos os índices dessa tabela. Isso diminuirá a quantidade de divisões no meio da página aumentando o tamanho da tabela / índice. Se você quiser seguir esse caminho, sugiro testar com o valor 80 e reduzir se a análise revelar que as divisões no meio da página ainda estão prejudicando o desempenho.

Minha sugestão é usar o OrderId. O OrderID deve, naturalmente, ser seqüencial e gerar mais divisões da página final, que são boas e esperadas com o crescimento da tabela. Além disso, essa abordagem funcionará melhor com o Particionamento de tabela se você optar por usar a coluna OrderDate como uma chave de partição. Em relação às consultas que usam constantemente o campo CódigoDoCliente, crie um índice não clusterizado para manipular essas consultas. Esse índice precisaria ser definido com o devido FILLFACTOR, pois sofrerá as divisões no meio da página mencionadas acima, embora não sejam tão ruins em geral, em contraste com se as divisões estavam ocorrendo no índice clusterizado.

A atividade em nosso banco de dados é de cerca de 85% de leituras e 15% de gravações.

CustomerID+ OrderID(e especificar um fator de preenchimento para permitir crescimento sem divisões) provavelmente é melhor se essa avaliação for verdadeira. Apenas verifique se a avaliação é precisa. Teste teste teste.

John Eisbrener
fonte
1
Observe que a inserção de um pedido para o último (ou somente) Cliente em uma página não é uma "divisão de página intermediária". Portanto, se os pedidos por cliente forem altos ou a largura da linha for grande, menos inserções de pedidos exigirão "divisões no meio da página".
David Browne - Microsoft