O índice em uma coluna de identidade deve ser não clusterizado?

19

Para uma tabela com coluna de identidade, um índice PK / exclusivo em cluster ou não em cluster deve ser criado para a coluna de identidade?

O motivo é que outros índices serão criados para consultas. Uma consulta que usa um índice não clusterizado (em um heap) e retorna colunas que não são cobertas pelo índice usará menos E / S lógica (LIO) porque não há etapas adicionais de busca de árvore b de índice clusterizado?

create table T (
  Id int identity(1,1) primary key, -- clustered or non-clustered? (surrogate key, may be used to join another table)
  A .... -- A, B, C have mixed data type of int, date, varchar, float, money, ....
  B ....
  C ....
  ....)

create index ix_A on T (A)
create index ix_..... -- Many indexes can be created for queries

-- Common query is query on A, B, C, ....
select A, B 
from T 
where A between @a and @a+5 -- This query will have less LIO if the PK is non-clustered (seek)

select A, B, C
from T 
where B between @a and @a+5 

....

A PK em cluster na coluna de identidade é boa porque:

  1. Aumenta monotonamente para que nenhuma página seja dividida ao inserir. Dizem que uma inserção em massa pode ser tão rápida quanto em uma tabela de pilha (não clusterizada)

  2. É estreito

No entanto, as consultas na pergunta serão mais rápidas sem a configuração em cluster?

** Atualização: ** E se o IdFK for de outras tabelas e ele for associado a algumas consultas?

u23432534
fonte
3
Não é melhor ou pior, depende.
Aaron Bertrand
1
@ypercube O link kejser.org/clustered-indexes-vs-heaps disse que o não-IC terá menos LIO.
U23432534
2
Eu li o artigo no passado e certamente aponta que há casos para um índice em cluster e casos para um heap. Nem tudo é preto ou todo branco.
precisa saber é o seguinte
4
Não tenho certeza de que sua resposta ao @ypercube satisfaça algum dos critérios citados pelo Sr. Kejser - pelo menos com os detalhes que você compartilhou. Em sua forma atual, não tenho certeza de que isso gere uma resposta útil, pois precisaria cobrir quase todos os cenários - o que já é feito no blog que você citou. Se você puder fornecer mais detalhes sobre seu cenário específico, talvez seja possível aplicar parte do conhecimento da publicação.
swasheck
2
Vai depender de coisas como: a) carga de trabalho (OLTP? OLAP? Etc?), B) tamanho (s) da tabela, c) forma normal, apenas para citar alguns. Você não forneceu detalhes sobre qualquer um desses fatores; portanto, qualquer recomendação seria baseada em suposições do seu ambiente. Além disso, você tentou criar um perfil das consultas que você está propondo (com buffers limpos) e obter os perfis de E / S específicos por configuração e ver por si mesmo?
swasheck

Respostas:

16

Por padrão, o PK está agrupado e, na maioria dos casos, isso é bom. No entanto, qual pergunta deve ser feita:

  • meu PK deve ser agrupado?
  • quais colunas serão a melhor chave para o meu índice em cluster?

PK e índice clusterizado são duas coisas diferentes:

  • PK é uma restrição. PK é usado para identificar linhas com exclusividade, mas não há noção de armazenamento. No entanto, por padrão (no SSMS), ele é imposto por um índice em cluster exclusivo se um índice em cluster ainda não estiver presente.
  • Índices em cluster é um tipo especial de índice que armazena dados de linha no nível da folha, o que significa que está sempre cobrindo. Todas as colunas, sejam elas parte da chave ou não, são armazenadas no nível da folha. Ele não precisa ser exclusivo; nesse caso, um uniquificador (4 bytes) é adicionado à chave em cluster.

Agora, terminamos com duas perguntas:

  • Como desejo identificar exclusivamente linhas na minha tabela (PK)
  • Como desejo armazená-lo no nível folha de um índice (Índice de Cluster)

Depende de como:

  • você cria seu modelo de dados
  • você consulta seus dados e escreve suas consultas
  • você insere ou atualiza seus dados
  • ...

Primeiro, você precisa de um índice em cluster? Se você inserir em massa, é mais eficiente armazenar dados não ordenados em um HEAP (versus dados ordenados em um cluster). Ele usa o RID (identificador de linha, 8 bytes) para identificar exclusivamente as linhas e armazená-las nas páginas.

O índice clusterizado não deve ser um valor aleatório. Os dados no nível da folha serão armazenados e ordenados pela chave de índice. Portanto, ele deve crescer continuamente para evitar fragmentação ou divisão de página. Se isso não puder ser alcançado pela PK, considere outra chave como candidato em cluster. O índice agrupado nas colunas de identificação, o GUID seqüencial ou mesmo algo como a data da inserção é bom do ponto de vista seqüencial, pois todas as linhas serão adicionadas à última página de folha. Por outro lado, embora o identificador exclusivo possa ser útil para as necessidades da sua empresa como PK, eles não devem ser agrupados (eles são ordenados / gerados aleatoriamente).

Se, após algumas análises de dados e consultas, você descobrir que usa o mesmo índice para obter seus dados antes de fazer uma pesquisa de chave na PK em cluster, considere-o como índice em cluster, embora possa não identificar exclusivamente seus dados.

A chave de índice em cluster é composta por todas as colunas que você deseja indexar. Uma coluna uniquefier (4 bytes) será adicionada se não houver restrição exclusiva nela (valor incremental para duplicatas, nulo caso contrário). Essa chave de índice será armazenada uma vez para cada linha no nível da folha de todos os seus índices não clusterizados. Alguns deles também serão armazenados várias vezes em níveis intermediários (ramificação) entre a raiz e o nível das folhas da árvore de índice (árvore B). Se a chave for muito grande, todo o índice não clusterizado ficará maior, exigirá mais armazenamento e mais IO, CPU, memória, ... Se você tiver um PK em nome + data de nascimento + país, é muito provável que essa chave não é um bom candidato. É muito grande para um índice em cluster. O identificador exclusivo usando NEWSEQUENTIALID () geralmente não é considerado uma chave estreita (16 bytes), embora seja seqüencial.

Depois que você descobrir como identificar linhas exclusivamente em sua tabela, poderá adicionar uma PK. Se você acha que não o usará em sua consulta, não o crie em cluster. Você ainda pode criar outro índice não clusterizado se precisar, em algum momento, consultá-lo. Observe que o PK criará automaticamente um índice exclusivo.

Os índices não agrupados sempre conterão a chave agrupada. No entanto, se as colunas indexadas (+ colunas principais) estiverem cobrindo, não haverá nenhuma pesquisa de chave no índice clusterizado. Não esqueça que você também pode adicionar Incluir e Onde a um índice não agrupado. (use-o com sabedoria)

O índice de cluster deve ser único e o mais estreito possível. O índice de cluster não deve mudar ao longo do tempo e deve ser inserido de forma incremental.

Agora é hora de escrever um pouco de SQL que criará a tabela, índices e restrições em cluster e não em cluster.

Isso tudo é teórico, porque não conhecemos seu modelo de dados e tipos de dados usados ​​(A e B).

Julien Vavasseur
fonte
11

Para uma tabela com uma chave primária (PK) em uma coluna de identidade, ela será agrupada por padrão. Poderia ser melhor como não clusterizado?

Se você está perguntando se o padrão de uma chave primária em uma coluna de identidade (em particular) deve ser não clusterizado, eu diria que não. A maioria das tabelas se beneficia de ter um índice em cluster, portanto, tornar o cluster o padrão para uma restrição de chave primária provavelmente é útil em geral, especialmente para novos usuários do SQL Server.

Como em praticamente qualquer opção, sempre existem circunstâncias diferentes em que uma deve ser preferida à outra, mas um DBA experiente deve estar ciente do padrão e substituí-lo quando apropriado. Consulte também as perguntas e respostas relacionadas: Quando uma chave primária deve ser declarada sem cluster? .

As consultas na pergunta serão mais rápidas sem a configuração em cluster?

Sim, mas com ressalvas.

As pesquisas de RID são realmente mais eficientes do que as principais pesquisas. Mesmo que todas as páginas necessárias estejam na memória (provavelmente para os níveis superiores de um índice), há um custo de CPU associado à navegação na árvore b do índice em cluster. Como conseqüência, o SQL Server normalmente pode executar muito mais pesquisas de RID do que pesquisas de chave por unidade de tempo de CPU.

Ressalvas

O exposto acima não costuma ser um fator determinante na decisão de estruturar uma tabela como uma pilha ou não. Teria que ser impraticável para evitar pesquisas (usando índices de cobertura), e o número de pesquisas teria que ser grande o suficiente para ter um efeito mensurável (e importante) no desempenho, considerando o ambiente de hardware e a carga de trabalho.

Não é realmente prático abordar todos os aspectos do debate sobre heap versus índice de cluster nesta resposta, mas direi que há relativamente poucas boas razões para preferir estruturar uma tabela como heap em geral. Para mim, escolher o tipo de design proposto na pergunta exigiria uma análise muito cuidadosa antes da implementação e teria que atender a um nível alto. Argumentos gerais sobre 'escalabilidade' não seriam suficientes.

Com relação à atualização da pergunta sobre junções, avaliar o impacto da perda do índice clusterizado nos planos de execução faria parte da análise mencionada acima. Se junções de loops aninhados forem usadas, é muito conveniente ter o índice de cluster na chave de junção, porque todas as colunas da linha estarão imediatamente disponíveis sem uma pesquisa.

Minha própria experiência foi que ter índices clusterizados exclusivos em colunas de identidade é muitas vezes benéfico, todas as coisas são consideradas. Eu achei os montes problemáticos em termos de gerenciamento de espaço e também devo mencionar que alguns recursos do SQL Server exigem um índice clusterizado exclusivo para funcionar.

Paul White diz que a GoFundMonica
fonte
8

Na verdade, você não precisa de um Índice de Cluster nem uma Chave Primária para ser criado, pois Índices Exclusivos e Índices Não Exclusivos podem lidar com o trabalho. O SQL Server oferece suporte a um índice clusterizado desde pelo menos a versão 1.1, mas a chave primária era apenas um "conceito" que os programadores aplicaram ao definir um índice exclusivo.

Mas parece que as Chaves Primárias e os Índices em Cluster são conceitos valiosos na maioria dos bancos de dados.

Vejamos a documentação do SQL Server para ver as descrições parciais de algumas opções de indexação, como mostrado abaixo.

Índice agrupado: https://msdn.microsoft.com/en-us/library/ms190457.aspx

  • 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 de índice.
  • Pode haver apenas um índice em cluster por tabela

Chave primária: https://msdn.microsoft.com/en-us/library/ms190457.aspx

  • Uma tabela pode conter apenas uma restrição PRIMARY KEY.

  • Todas as colunas definidas em uma restrição PRIMARY KEY devem ser definidas como NOT NULL.

  • A chave primária pode ser criada como um índice clusterizado (o padrão se não houver índice clusterizado) ou um índice não clusterizado.

Índice exclusivo: https://msdn.microsoft.com/en-us/library/ms187019.aspx

  • Quando você cria uma restrição UNIQUE, um índice exclusivo não clusterizado é criado para impor uma restrição UNIQUE por padrão.

  • Você pode especificar um índice clusterizado UNIQUE se um índice clusterizado ainda não existir para a tabela.

Isso significa que sua pergunta sobre índices clusterizados e chaves primárias é realmente sobre alguns dos seguintes problemas. Observe que nem todas as tabelas se beneficiam do mesmo plano de indexação.

Quando eu me beneficiaria com a Chave Primária separada do Índice de Cluster?

Talvez quando o Índice de Cluster seja Amplo (por exemplo, 5 colunas de informações textuais, mas a Chave Primária é pequena (INT ou BIGINT), como você parece estar descrevendo.

  • Um amplo índice clusterizado permitiria selecionar rapidamente linhas do índice para um subconjunto de consultas que fornecem respostas seriais do índice clusterizado (também conhecido como tabela ). Por exemplo, um índice agrupado de 5 colunas suportaria a varredura das colunas C1, C2, C3, C4, C5 ou C1, C2, C3, C4 e assim por diante até C1.
  • Nota: Se as linhas forem grandes, isso poderá fornecer alguns benefícios de velocidade na seleção do conjunto de linhas em série , especialmente se outras colunas da tabela forem incluídas regularmente no conjunto de resultados.
  • Nesse caso, você pode usar a Chave Primária para integridade referencial, a fim de fornecer o valor necessário como uma Chave Estrangeira para restringir linhas em outras tabelas. O PK é pequeno e, portanto, o FK é um pequeno impacto no tamanho da (s) tabela (s) referenciada (s).
  • No entanto, observe que qualquer índice criado em uma tabela que tenha um Índice em Cluster incluirá todas as colunas do cluster nos outros índices que você criar nesta tabela. Um amplo Índice em Cluster expandiria o tamanho de todos os índices não em cluster nessa tabela.

Você deve tornar a Chave Primária sozinha o Índice de Cluster?

  • Se você possui uma Chave Primária pequena (INT ou BIGINT) e é o Índice de Cluster, a sobrecarga das colunas do cluster é relativamente pequena. Embora a Chave Primária em Cluster neste caso também exista em todos os índices desta tabela, é um preço menor a pagar do que o Wide Cluster discutido acima.

  • Esse índice de cluster de chave primária geralmente não oferece diretamente um caminho fácil para a seleção serial de muitas linhas.

  • Agora que você criou uma Chave Primária em Cluster, e as outras colunas que planejava incluir no Índice em Cluster ?

  • Crie um índice Exclusivo (ou Não Exclusivo) conforme necessário para indexar esse amplo critério de pesquisa das colunas C1, C2, C3, C4, C5. Os valores neste índice "Imitation Clustered" podem servir como um caminho de pesquisa mais rápido para essas 5 colunas. Se houver uma coluna ou duas não indexadas que também são selecionadas regularmente, elas podem ser incluídas no índice com INCLUDE (Doctor_Name, Diagnosis_Synopsis).

Embora eu ache úteis os Índices em Cluster e as Chaves Primárias simples, existem algumas boas razões para pensar em usá-los em uma tabela ou em um banco de dados.

Você precisa de um índice de cluster?

  • Se você criar índices (índices exclusivos e índices não exclusivos) e definir a chave primária sem a sobrecarga de ser um índice clusterizado, poderá descobrir que os índices mais restritos fornecem o que você precisa para suas consultas.

  • Existem alguns comportamentos úteis nos índices clusterizados e nas chaves primárias, mas lembre-se de que são realmente os índices que mais importam. Projete a estratégia de indexação para levar em conta as realidades do seu aplicativo. Talvez seja OneBigTablenecessário ter uma estratégia de indexação diferente da usada na maioria das tabelas.

  • Sem um índice agrupado, seus dados serão armazenados como um heap com o Row Identifier (RID), que não é um bom mecanismo de pesquisa. Mas, como mencionado anteriormente, você pode criar índices únicos e não exclusivos para lidar com suas consultas.

O que agora leva você a considerar Heaps:

Montes e índices: https://msdn.microsoft.com/en-us/library/hh213609.aspx

  • Quando uma tabela é armazenada como um heap, as linhas individuais são identificadas por referência a um identificador de linha (RID) que consiste no número do arquivo, no número da página de dados e no slot da página. O ID da linha é uma estrutura pequena e eficiente. (Mas não é um índice .)
  • Às vezes, os arquitetos de dados usam pilhas quando os dados são sempre acessados ​​por índices não clusterizados e o RID é menor que uma chave de índice em cluster .

Mas se você também possui alguns 'pontos de acesso' em um grande conjunto de dados, também pode procurar outro tipo de índice:

Índice Filtrado: https://msdn.microsoft.com/en-us/library/cc280372.aspx

  • Um índice filtrado bem projetado melhora o desempenho da consulta e a qualidade do plano de execução, porque é menor que um índice não clusterizado de tabela completa e possui estatísticas filtradas. As estatísticas filtradas são mais precisas que as estatísticas de tabela completa porque cobrem apenas as linhas no índice filtrado .

  • Os índices filtrados têm várias restrições descritas no link para índices filtrados.

No entanto, se você estiver interessado em pensar nessa possibilidade de ignorar Chaves Primárias e Índices em Cluster, leia a publicação de Markus Winand no link abaixo. Ele demonstra seus motivos, com alguns exemplos de código, para sugerir que às vezes é uma boa ideia deixar de usar esses recursos.

http://use-the-index-luke.com/blog/2014-01/unreasonable-defaults-primary-key-clustering-key

Mas tudo finalmente volta a entender seu aplicativo e projetar o código, as tabelas, os índices e assim por diante para se adequar ao trabalho que você está fazendo.

RLF
fonte
Pelo que vale a pena, no meu trabalho diário, se eu encontrar uma tabela que seja um monte, considero que provavelmente seja um erro e verifique com os desenvolvedores se foi feito um monte intencionalmente.
RLF
-2

Alguns pontos a considerar.

Embora um índice (agrupado ou não) em um valor crescente monótono economize as divisões de página durante inserções em massa, ele cria um novo ponto de acesso no final do índice. Embora possa não ser um problema com uma inserção em massa de um único encadeamento, definitivamente aumentará a contenção para um aplicativo multithread inserindo novas tuplas a uma taxa alta, pois os encadeamentos competirão constantemente pelo acesso à última página do índice.

Agrupar a tabela com base em uma PK substituta (identidade) raramente é benéfico. Essa chave primária é usada principalmente para acessar tuplas individuais, uma de cada vez, ou verificar o índice inteiro em busca de junções. Em ambos os casos, não importa se o índice está em cluster ou não (com exceção das junções de mesclagem, pode ser, mas com que frequência elas são?)

Acho que você se beneficiará mais de um índice agrupado que cobre consultas que solicitam uma verificação de intervalo de chaves e predicados adicionais referentes a outras colunas.

mustaccio
fonte
Quão alta deve ser a taxa para que isso realmente se torne um problema?
precisa saber é o seguinte
@ypercube posso dizer "depende"? Porque faz. Na ausência de gatilhos na tabela, eu esperaria começar a enfrentar uma contenção com uma dúzia de threads, totalizando 1K inserções por segundo.
mustaccio
Não discordo, mas estava perguntando até que ponto alguém pode ir com um único hot spot. Lembro-me de ver um artigo sobre a inserção de 30 mil linhas por segundo em uma tabela com IDENTITY como IC (se a memória me servir bem), mas não consigo encontrar a postagem do blog.
precisa saber é o seguinte
Essa discussão é inútil na ausência de uma carga de trabalho concreta em execução em um esquema concreto em hardware específico. Espero que todos possamos concordar que um índice em uma sequência crescente monótona criará um "ponto de acesso"; se isso criará um gargalo inaceitável e se alguém deve se preocupar com isso ou não depende das circunstâncias.
mustaccio