Strings como chaves primárias no banco de dados SQL

178

Eu não estou muito familiarizado com bancos de dados e as teorias por trás de como eles funcionam. É mais lento do ponto de vista de desempenho (inserção / atualização / consulta) usar Strings para Chaves Primárias do que números inteiros?

mainstringargs
fonte

Respostas:

191

Tecnicamente sim, mas se uma string faz sentido ser a chave primária, você provavelmente deve usá-la. Tudo depende do tamanho da tabela para a qual você está fabricando e do comprimento da string que será a chave principal (cadeias mais longas == mais difíceis de comparar). Eu não usaria necessariamente uma string para uma tabela que possui milhões de linhas, mas a quantidade de lentidão no desempenho que você obterá usando uma string em tabelas menores será minúscula para as dores de cabeça que você pode ter ao ter um número inteiro que não significa qualquer coisa em relação aos dados.

kemiller2002
fonte
11
não dependeria do banco de dados? Eu pensaria que uma string corretamente indexada não seria muito mais lenta se fosse de um número?
24519 Ryan Guill
2
Eu concordo que há muitas variáveis ​​a serem consideradas. (No sqlserver), vimos problemas reais de desempenho com o uso de strings com comprimentos entre adolescentes de médio a alto e acima, mesmo quando indexados. Compre você está certo, há coisas para superar esse hardware, por exemplo.
kemiller2002
1
Justo. Eu concordaria que, se uma string faz sentido, é isso que você deve usar. Eu diria também que há definitivamente momentos para os campos GUID ou UUID nos bancos de dados em que um campo de incremento automático não funcionaria.
24519 Ryan Guill
7
Também tenha em mente que muitas vezes há uma diferença muito grande entre um CHAR e VARCHAR ao fazer comparações de índices
Tom H
7
O número de comentários desta resposta deixa claro como é incompleta. Mencionar a indexação teria sido a resposta mínima aceitável.
Pedro Rolo
74

Outro problema com o uso de Strings como chave primária é que, como o índice é constantemente colocado em ordem seqüencial, quando uma nova chave é criada, que fica no meio da ordem, o índice precisa ser reequilibrado ... se você usar um auto número inteiro, a nova chave é apenas adicionada ao final do índice.

Jeff Martin
fonte
2
Isso pode causar "pontos quentes" para novas inserções. Desde que você esteja gerenciando seu banco de dados corretamente, você deve ter espaço extra em suas páginas para inserções de qualquer maneira e as divisões de páginas devem ser raras.
Tom H
20
é quando chaves primárias são agrupadas. você também pode criá-los sem cluster.
Aprendendo
Os XIDs são solicitados, o que pode ajudar se você apenas usar xid strings
Sinaesthetic
22

Insere em uma tabela com um índice clusterizado onde a inserção ocorre no meio da sequência NÃO faz com que o índice seja reescrito. Não faz com que as páginas que compõem os dados sejam reescritas. Se houver espaço na página para onde a linha irá, ela será colocada nessa página. A página única será reformatada para colocar a linha no lugar certo na página. Quando a página estiver cheia, uma divisão de página ocorrerá, com metade das linhas na página indo para uma página e metade indo para a outra. As páginas são vinculadas novamente à lista vinculada de páginas que compõem os dados de uma tabela que possui o índice em cluster. No máximo, você acabará escrevendo 2 páginas de banco de dados.

Mark Thompson
fonte
Boa explicação. Mas isso é verdade para todos os bancos de dados SQL? Ouvi falar de problemas de desempenho do MySQL ao usar UUID aleatório como chave primária.
precisa saber é
13

As strings são mais lentas nas junções e, na vida real, raramente são realmente únicas (mesmo quando deveriam ser). A única vantagem é que eles podem reduzir o número de junções se você estiver ingressando na tabela principal apenas para obter o nome. No entanto, as strings também estão sujeitas a alterações, criando o problema de precisar corrigir todos os registros relacionados quando o nome da empresa muda ou a pessoa se casa. Isso pode ser um enorme impacto no desempenho e, se todas as tabelas que devem ser relacionadas de alguma forma não estiverem relacionadas (isso acontece com mais frequência do que você pensa), também é possível que haja incompatibilidades de dados. Um número inteiro que nunca será alterado ao longo da vida útil do registro é uma opção muito mais segura do ponto de vista da integridade dos dados e do ponto de vista do desempenho. As chaves naturais geralmente não são tão boas para a manutenção dos dados.

Também quero ressaltar que o melhor dos dois mundos é usar uma chave de incremento automático (ou, em alguns casos especializados, um GUID) como PK e, em seguida, colocar um índice exclusivo na chave natural. Você obtém as junções mais rápidas, não recebe registros duplicados e não precisa atualizar um milhão de registros filhos porque o nome da empresa mudou.

HLGEM
fonte
26
Seqüências de caracteres que são boas candidatas a PKs não têm duplicatas - caso contrário, não seriam boas candidatas a uma PK. Pense nos códigos ICD-9, nos códigos dos países, nos VIN. Usar um nome como exemplo de um problema com chaves naturais é equivocado, porque elas nunca devem ser candidatas.
Tom H
6
@ Tom H: Os códigos ISO do condado mudam. [ en.wikipedia.org/wiki/ISO_3166-1#Editions_and_changes ] Como resposta a uma pergunta relacionada, disse [ stackoverflow.com/questions/925266/… ] "Para as CHAVES PRIMÁRIAS, verifique se a sua exclusividade está sob seu controle"
Steve Schnepp
4
@SteveSchnepp: sim, e a ISO é o órgão confiável para gerenciar essa mudança. Por outro lado, quando você precisa mesclar sua sequência monotônica de valores inteiros incrementais com os de outra pessoa, você fica por conta própria;);
após o dia
1
Concordo que os nomes não devem ser considerados uma chave, acabei de ver muitas vezes quando eram.
HLGEM
1
@onedaywhen fundindo dois sequência monótona de incrementação inteiro é facilmente feito através de prefixação ou sufixação :)
Steve Schnepp
6

Não importa o que você usa como chave primária, desde que seja ÚNICO. Se você se preocupa com a velocidade ou com o bom design do banco de dados, use o int, a menos que planeje replicar dados, use um GUID.

Se este é um banco de dados de acesso ou algum aplicativo minúsculo, quem realmente se importa. Eu acho que a razão pela qual a maioria de nós, desenvolvedores, tapa o velho int ou guid na frente é porque os projetos têm uma maneira de crescer conosco, e você quer deixar a opção de crescer.

Al Katawazi
fonte
5

Variáveis ​​demais. Depende do tamanho da tabela, dos índices, da natureza do domínio da chave de cadeia ...

Geralmente , os números inteiros serão mais rápidos. Mas a diferença será grande o suficiente para se importar? É difícil dizer.

Além disso, qual é a sua motivação para escolher strings? As teclas numéricas de incremento automático também costumam ser muito mais fáceis . É semântica? Conveniência? Replicação / preocupações desconectadas? Sua resposta aqui pode limitar suas opções. Isso também lembra uma terceira opção "híbrida" que você está esquecendo: Guids.

Joel Coehoorn
fonte
isso não faz sentido, o que você quer dizer com isso?
HLGEM 5/02/09
@HLGEM: Se eu o entendo escrever, ele significa sincronizar registros criados em um laptop com o banco de dados principal.
Joel Coehoorn
Quero dizer, tenho dois bancos de dados separados com as mesmas entidades, apenas um é atualizado com menos frequência para fins de armazenamento persistente. Se eu consulta para a entidade "Califórnia" na base de dados A, eu quero que seja fundamentalmente o mesmo "California" na base de dados B.
mainstringargs
1
E é como sincronizar registros criados em um laptop, pois é o mesmo problema: os registros criados em um local não devem entrar em conflito com os registros criados em outro. Uma solução possível aqui são as chaves Guid.
Joel Coehoorn
5

Não se preocupe com o desempenho até obter um design simples e consistente que concorde com o assunto descrito pelos dados e que se adapte bem ao uso pretendido dos dados. Então, se surgirem problemas de desempenho, você poderá lidar com eles ajustando o sistema.

Nesse caso, é quase sempre melhor usar uma string como chave primária natural, desde que você possa confiar nela. Não se preocupe se for uma string, contanto que ela seja razoavelmente curta, digamos cerca de 25 caracteres no máximo. Você não pagará um preço alto em termos de desempenho.

As pessoas que inserem dados ou as fontes de dados automáticas sempre fornecem um valor para a suposta chave natural ou às vezes são omitidas? Ocasionalmente, está errado nos dados de entrada? Em caso afirmativo, como os erros são detectados e corrigidos?

Os programadores e usuários interativos que especificam consultas podem usar a chave natural para obter o que desejam?

Se você não pode confiar na chave natural, invente um substituto. Se você inventar um substituto, também poderá inventar um número inteiro. Então você precisa se preocupar com o motivo de ocultar o substituto da comunidade de usuários. Alguns desenvolvedores que não ocultaram a chave substituta passaram a se arrepender.

Walter Mitty
fonte
3

Os índices implicam muitas comparações.

Normalmente, as strings são mais longas que os números inteiros e as regras de intercalação podem ser aplicadas para comparação, portanto, comparar strings é geralmente uma tarefa mais intensiva em termos computacionais do que comparar números inteiros.

Às vezes, porém, é mais rápido usar uma string como chave primária do que fazer uma junção extra com uma string to numerical idtabela.

Quassnoi
fonte
2

Sim, mas, a menos que você espere ter milhões de linhas, não usar uma chave baseada em string porque é mais lenta geralmente é "otimização prematura". Afinal, as strings são armazenadas como números grandes, enquanto as teclas numéricas geralmente são armazenadas como números menores.

Uma coisa a ser observada, no entanto, é se você agrupou índices em uma chave qualquer e está executando um grande número de inserções que não são seqüenciais no índice. Cada linha gravada fará com que o índice seja reescrito. se você estiver fazendo inserções em lote, isso pode realmente atrasar o processo.

Sim - aquele Jake.
fonte
2

Dois motivos para usar números inteiros para colunas PK:

  1. Podemos definir a identidade para o campo inteiro que é incrementado automaticamente.

  2. Quando criamos PKs, o banco de dados cria um índice (Cluster ou Não Cluster) que classifica os dados antes de serem armazenados na tabela. Ao usar uma identidade em uma PK, o otimizador não precisa verificar a ordem de classificação antes de salvar um registro. Isso melhora o desempenho em grandes tabelas.

Jatinder Singh
fonte
1

Qual é o seu motivo para ter uma string como chave primária?

Eu apenas definiria a chave primária como um campo inteiro com incremento automático e colocaria um índice no campo string.

Dessa forma, se você fizer pesquisas na mesa, elas deverão ser relativamente rápidas, e todas as suas junções e pesquisas normais não serão afetadas em sua velocidade.

Você também pode controlar a quantidade do campo de sequência que é indexada. Em outras palavras, você pode dizer "indexe apenas os 5 primeiros caracteres" se achar que isso será suficiente. Ou, se seus dados puderem ser relativamente semelhantes, você poderá indexar todo o campo.

John Bubriski
fonte
3
Eu acho que colocar qualquer inteligência em uma chave está pedindo problemas. Eles permanecerão únicos? Eles começaram todos os números de conta com a abreviação do estado no início apenas para a mudança do cliente. Atualizar um campo - não há problema - todas as tabelas vinculadas pelo número da conta - que bagunça.
9119 JeffO
1
Um exemplo de uso de uma string como PK pode ser uma tabela de configurações. por exemplo, settingNamePK, isUserEditable, isCustomerEditable etc. Então, se você quiser modificar o comportamento da configuração "UPDATE setting SET ... WHERE settingNamePK = 'dailyWorkObligation'" é muito melhor do que usar IDs e armazenar em algum lugar o mapeamento dos IDs. É claro que você pode ter um PK inteiro e ter o nome da configuração como outra chave exclusiva.
MeatPopsicle
Com a chave primária sendo um número inteiro incrementado automaticamente, as inserções também não devem ser afetadas em sua velocidade?
Dennis
Para desenvolvedores curiosos do Rails, veja como especificar um tamanho de índice . Observe que o SQLite não suporta o comprimento do índice.
Dennis
1

Do ponto de vista do desempenho - Sim, a string (PK) diminuirá o desempenho quando comparado ao desempenho obtido usando um número inteiro (PK), em que PK ---> Primary Key.

Do ponto de vista dos requisitos - Embora isso ainda não faça parte da sua pergunta, eu gostaria de mencionar. Quando lidamos com dados enormes em tabelas diferentes, geralmente procuramos o conjunto provável de chaves que podem ser definidas para uma tabela específica. Isso ocorre principalmente porque existem muitas tabelas e, principalmente, cada uma delas pode estar relacionada à outra através de alguma relação (um conceito de chave estrangeira). Portanto, nem sempre podemos escolher um número inteiro como Chave Primária, pelo contrário, optamos por uma combinação de 3, 4 ou 5 atributos como chave primária para essas tabelas. E essas chaves podem ser usadas como uma chave estrangeira quando relacionarmos os registros com alguma outra tabela. Isso torna útil relacionar os registros entre diferentes tabelas quando necessário.

Portanto, para uso ideal - sempre fazemos uma combinação de 1 ou 2 números inteiros com 1 ou 2 atributos de sequência, mas novamente apenas se necessário.


fonte
0

Pode haver um grande mal-entendido relacionado a string no banco de dados. Quase todo mundo pensou que a representação de números no banco de dados é mais compacta do que nas seqüências de caracteres. Eles acham que nos números db-s são representados como na memória. MAS não é verdade. Na maioria dos casos, a representação numérica está mais próxima de Uma string, como a representação, como em outras.

A velocidade do uso de número ou string é mais dependente da indexação do que do próprio tipo.

takacsot
fonte
0

Por padrão, ASPNetUserIds tem 128 caracteres e o desempenho é bom.

Se a chave TEM de ser único na tabela deve ser a chave. Aqui está o porquê;

chave de cadeia primária = relacionamentos corretos de banco de dados, 1 chave de cadeia (a primária) e 1 índice de cadeia (a primária).

A outra opção é um int típico Key, mas se a cadeia TEM de ser único você ainda vai provavelmente precisará adicionar um índice por causa de consultas non-stop para validar ou verificar se o seu único.

Portanto, usando uma chave de identidade int = Relacionamentos de banco de dados incorretos, 1 chave int (Primária), 1 int índice (Primária), provavelmente uma Index de string exclusiva e ter que validar manualmente a mesma string não existe (algo como uma verificação sql talvez )

Para obter um melhor desempenho usando um int sobre uma corda para a chave primária, quando a corda TEM de ser único, ele teria que ser uma situação muito estranha. Eu sempre preferi usar chaves de string. E como uma boa regra geral, não desnormalize um banco de dados até que PRECISA .

JPoole
fonte