Estou desenvolvendo um banco de dados SQL Server 2012 e tenho uma dúvida sobre as colunas nvarchar como chaves primárias.
Eu tenho esta tabela:
CREATE TABLE [dbo].[CODES]
(
[ID_CODE] [bigint] IDENTITY(1,1) NOT NULL,
[CODE_LEVEL] [tinyint] NOT NULL,
[CODE] [nvarchar](20) NOT NULL,
[FLAG] [tinyint] NOT NULL,
[IS_TRANSMITTED] [bit] NOT NULL DEFAULT 0,
CONSTRAINT [PK_CODES] PRIMARY KEY CLUSTERED
(
[CODE_LEVEL] ASC,
[CODE] ASC
)
)
Mas agora eu quero usar a [CODE]
coluna como chave primária e remover a [ID_CODE]
coluna.
Existe algum problema ou penalidade se eu tiver uma NVARCHAR
coluna como PRIMARY KEY
?
[CODE]
O valor da coluna deve ser exclusivo, portanto, pensei em definir uma UNIQUE
restrição para essa coluna.
Preciso usar [CODE]
como chave primária ou é melhor se eu definir uma UNIQUE
restrição na [CODE]
coluna?
sql-server
primary-key
unique-constraint
VansFannel
fonte
fonte
CODE
coluna deve ser única, mas não uma Chave Primária. Eu suspeito que ele carrega informações. Se essas informações puderemCODE
ser alteradas de alguma forma, você deverá mudar ou estar desatualizado. Isso tornaria sua Chave Primária volátil, e não consigo ver isso terminando bem. É melhor deixar seu PK ser apenas uma chave, e seu CÓDIGO pode fazer o que quiser. Apenas uma opinião.Respostas:
Sim, existem consequências negativas para o uso de uma string em vez de um tipo numérico para uma Chave Primária, e ainda mais se o PK estiver em Cluster (o que de fato é o seu caso). No entanto, o grau em que você vê o (s) efeito (s) do uso de um campo de sequência é uma função de a) quantas linhas estão nesta tabela eb) quantas linhas em outras tabelas têm Chave Estrangeira para este PK. Se você tiver apenas 10k linhas nesta tabela e 100k linhas em algumas outras tabelas que FK a esta tabela através desse campo, talvez não seja tão perceptível. Mas esses efeitos certamente se tornam mais visíveis à medida que a contagem de linhas aumenta.
Você precisa considerar que os campos em um Índice de cluster são transferidos para índices não de cluster. Portanto, você não está apenas olhando até 40 bytes por linha, mas (40 * some_number) bytes. E em todas as tabelas FK, você tem os mesmos 40 bytes na linha e, mais frequentemente, haverá um índice Não-Clusterizado nesse campo, pois está sendo usado em JOINs, portanto, agora é realmente duplicado em todas as tabelas que FK este. Se alguém está inclinado a pensar que 40 bytes * 1 milhão de linhas * 10 cópias não são motivo de preocupação, consulte o meu artigo O disco é barato! ORLY? que detalha todas (ou pelo menos a maioria) das áreas afetadas por esta decisão.
A outra coisa a considerar é que filtrar e classificar strings, especialmente quando não estiver usando um agrupamento binário (presumo que você esteja usando o padrão de banco de dados que normalmente não diferencia maiúsculas de minúsculas) é muito menos eficiente (ou seja, leva mais tempo) do que quando usa
INT
/BIGINT
. Isso afeta todas as consultas que filtram / ingressam / classificam nesse campo.Portanto, usar algo como
CHAR(5)
provavelmente seria bom para um PK em cluster, mas principalmente se também fosse definido comCOLLATE Latin1_General_100_BIN2
(ou algo parecido).E o valor de
[CODE]
alguma vez pode mudar? Se sim, é mais um motivo para não usá-lo como PK (mesmo que você defina os FKsON UPDATE CASCADE
). Se não puder ou nunca mudar, tudo bem, mas ainda há motivos mais do que suficientes para não usá-lo como um PK em cluster.Obviamente, a pergunta pode ser formulada incorretamente, pois parece que você já possui esse campo no seu PK.
Independentemente disso, sua melhor opção, de longe, é usar
[ID_CODE]
como PK em cluster, usar esse campo em tabelas relacionadas como FK e manter[CODE]
comoUNIQUE INDEX
(o que significa que é uma "chave alternativa").Atualizar
Um pouco mais de informação com base nesta pergunta em um comentário a esta resposta:
Tudo isso depende de muitos fatores, alguns dos quais eu já mencionei, mas que reafirmaremos:
Uma Chave Primária é como a linha individual é identificada, independentemente de ser referenciada por Chaves Estrangeiras. Como o sistema identifica internamente a linha está relacionado, mas não necessariamente o mesmo, como seus usuários se identificam / nessa linha. Qualquer coluna NOT NULL com dados exclusivos pode funcionar, mas há questões de praticidade a serem consideradas, especialmente se a PK for, de fato, referenciada por quaisquer FKs. Por exemplo, os GUIDs são únicos e algumas pessoas realmente gostam de usá-los por vários motivos, mas são muito ruins para índices de cluster (
NEWSEQUENTIALID
é melhor, mas não perfeito). Por outro lado, os GUIDs são ótimos como chaves alternativas e são usados pelo aplicativo para procurar a linha, mas os JOINs ainda são feitos usando uma PK INT (ou similar).Até agora, você não nos disse como o
[CODE]
campo se encaixa no sistema de todos os ângulos, além de mencionar agora que é assim que você procura linhas, mas isso é para todas as consultas ou apenas algumas? Conseqüentemente:Em relação ao
[CODE]
valor:Em relação a esta tabela:
[CODE]
ou[ID_CODE]
) são usados em outras tabelas, mesmo que não sejam explicitamente com chave estrangeira?[CODE]
o único campo é usado para obter linhas individuais, qual é a finalidade do[ID_CODE]
campo? Se não for usado, por que tê-lo em primeiro lugar (que pode depender da resposta para "O[CODE]
campo pode mudar?")?Esta decisão não pode ser tomada puramente na questão de "NVARCHAR sim ou não?". Mais uma vez direi que, de um modo geral, não acho que seja uma boa ideia, mas certamente há momentos em que está bem. Dado tão poucos campos nesta tabela, não é provável que exista mais, ou pelo menos não muitos, índices. Portanto, você pode estar bem de qualquer maneira
[CODE]
como o Índice de Cluster. E se nenhuma outra tabela fizer referência a essa tabela, você também poderá fazer o PK. Mas, se outras tabelas fizerem referência a essa tabela, eu optaria pelo[ID_CODE]
campo como PK, mesmo se Não estiver em cluster.fonte
[ID_CODE]
, comoPRIMARY KEY
, a melhor opção se eu usar a[CODE]
coluna para procurar a tabela?Você precisa separar os conceitos:
chave primária é um conceito de design , uma propriedade lógica das entradas na tabela. Deve ser imutável durante a vida útil da entrada da tabela e deve ser a chave usada no aplicativo para referenciar a entrada.
índice clusterizado é um conceito de armazenamento , uma propriedade física. Deve ser o caminho de acesso mais comum para consultas, deve servir para satisfazer o índice de cobertura na maioria dos casos e atender ao maior número possível de consultas de intervalo.
Não é necessário que a chave primária seja o índice em cluster. Você pode ter
ID_CODE
como PK e(CODE_LEVEL, CODE)
como chave em cluster. Ou o contrário.Uma chave agrupada maior tem algumas repercussões negativas, pois a chave mais ampla significa menor densidade nas páginas de índice e tamanho maior consumido em todos os índices não agrupados. já houve toneladas de tinta derramadas sobre esse tópico, por exemplo. start from Mais considerações sobre a chave de cluster - o debate sobre o índice em cluster continua! .
Mas a questão principal é que a escolha da chave de índice clusterizado é principalmente uma troca. Por um lado, você tem requisitos de tamanho de armazenamento, com repercussões gerais no desempenho (chave maior -> tamanho maior -> mais IO, e a largura de banda de IO é provavelmente o recurso mais escasso que você possui). Por outro lado, escolher a chave em cluster incorreta em nome da economia de espaço pode ter consequências no desempenho da consulta, geralmente piores que os problemas resultantes de uma chave ampla.
Quanto à escolha da chave primária, isso nem deve ser um problema: seu modelo de dados, sua lógica de aplicativo deve ditar qual é a chave primária.
Dito isto, o meu 2c: não
NVARCHAR(20)
é amplo. É um tamanho de chave agrupada perfeitamente aceitável, mesmo para uma tabela grande.fonte
[ID_CODE]
, comoPRIMARY KEY
, a melhor opção se eu usar a[CODE]
coluna (e talvez[CODE_LEVEL]
) para procurar a tabela?[CODE]
coluna como chave primária.Eu nunca permitiria que alguém fizesse
nvarchar(20)
um PK no meu banco de dados. Você perde espaço em disco e cache de memória. Todo índice nessa tabela e todos os FKs replicam esse amplo valor. Talvez um caractere (20), se puderem justificá-lo. Em que tipo de dados você está tentando armazenarCODE
? Você realmente precisa armazenar caracteres nvarchar? Costumo fazer com que os valores "internos" das PKs não sejam vistos pelos usuários e tento manter os valores exibidos separadamente. Às vezes, os valores exibidos precisam ser alterados, o que se torna muito problemático com PKs + FKs.Além disso, você percebe que uma 'identidade bigint (1,1)' pode incrementar até 9.223.372.036.854.775.807?
A menos que você esteja criando esse banco de dados para o Google, um normal
int identity (1,1)
com limite de mais de 2 bilhões não será suficiente?fonte
[ID_CODE]
, comoPRIMARY KEY
, a melhor opção se eu usar a[CODE]
coluna para procurar a tabela? Obrigado.Não deve haver nenhuma penalidade inerente / perceptível que não seja o risco de usar teclas largas ao usar nvarchar / varchar, se não estiver ciente. Especialmente se você começar a combiná-los em chaves compostas.
Mas no seu exemplo de (20) comprimento, você deve estar bem e eu não me preocuparia muito com isso. Porque se CODE é como você consulta principalmente seus dados - um índice clusterizado parece muito sensato.
No entanto, você deve considerar se realmente deseja uma chave primária ou apenas um índice exclusivo (em cluster). Há uma (pequena) diferença entre o índice em cluster e a chave primária (basicamente - chave primária identifica seus dados, mas o índice é como você consulta dados); portanto, se desejar, você pode facilmente criar seu ID_Code como uma chave primária e crie um índice clusterizado exclusivo sobre CODE. (aviso: o SQL Server transforma automaticamente sua Chave Primária em um índice em cluster, a menos que você tenha criado manualmente o índice em cluster)
Considere também se você realmente precisa do ID_Code agora que possui um CÓDIGO exclusivo.
fonte
NVARCHAR(20)
tem 40 bytes de tamanho (máximo) e, como é uma coluna de comprimento variável , não é realmente a melhor opção para um índice em cluster.ID_CODE
ser umBIGINT IDENTITY
seria a escolha muito melhor aqui!