Usar endereço de email como chave primária?

234

O endereço de email é um candidato ruim para o primário quando comparado aos números com incremento automático?

Nosso aplicativo da web precisa que o endereço de email seja exclusivo no sistema. Então, pensei em usar o endereço de email como chave primária. No entanto, meu colega sugere que a comparação de strings será mais lenta que a comparação de números inteiros.

É um motivo válido para não usar o email como chave primária?

Nós estamos usando PostgreSQL.

Robert
fonte
5
O que você quer dizer com 'primário'? Se o endereço de email precisar ser exclusivo, é uma chave e requer uma restrição exclusiva. Se você decide 'promover' o fato de ser 'primário' é arbitrário, a menos que haja uma razão prática para fazê-lo, por exemplo, otimizar um sistema com desempenho insatisfatório.
precisa saber é o seguinte
7
Se você deseja que seu banco de dados imponha um endereço de email exclusivo, crie uma coluna com um índice exclusivo, mas não o use como chave primária.
James Westgate
104
@robert E se alguém quiser alterar seu endereço de email? Você vai mudar todas as chaves estrangeiras também?
Systempuntoout
3
@ onedaywhen - quase nenhuma diferença, mas a chave primária será agrupada por padrão, enquanto um índice exclusivo não será. Você ainda vai querer definir a chave primária que será a chave de pesquisa padrão único registro, o índice exclusivo apenas reforça a exclusividade da coluna durante um índice normal
James Westgate
3
@ James Westgate: Para sua informação, não existe o agrupamento automático no PostgreSQL. Uma CHAVE PRIMÁRIA é implementada no disco exatamente da mesma forma que um ÍNDICE ÚNICO, onde todos os campos NÃO são NULL.
Matthew Wood

Respostas:

283

A comparação de strings é mais lenta que a comparação int. No entanto, isso não importa se você simplesmente recupera um usuário do banco de dados usando o endereço de email. É importante se você tiver consultas complexas com várias junções.

Se você armazenar informações sobre usuários em várias tabelas, as chaves estrangeiras da tabela de usuários serão o endereço de email. Isso significa que você armazena o endereço de email várias vezes.

Sjoerd
fonte
11
@ Sjoerd: A questão não é que o endereço de email seja armazenado várias vezes, embora isso seja definitivamente ineficiente, mas quem se importa com o espaço no disco rígido hoje. A maioria das empresas não possui escala no Google, o que importa. O problema é que o endereço de email não pode ser alterado posteriormente, porque é uma chave primária e referenciada como chave estrangeira.
Stefan Steiger
@StefanSteiger Quem disse algo sobre o espaço no disco rígido? Qualquer coisa que você armazena vai ocupar espaço na RAM.
Jonathan Allen
Caso alguém se pergunte, como eu, uma chave GUID seria equivalente a uma chave de e-mail, eu acho.
tofutim
178

Também apontarei que o e-mail é uma péssima escolha para criar um campo único, existem pessoas e até pequenas empresas que compartilham um endereço de e-mail. E, como números de telefone, os e-mails podem ser reutilizados. [email protected] pode facilmente pertencer a John Smith um ano e Julia Smith dois anos depois.

Outro problema com os e-mails é que eles mudam com frequência. Se você estiver ingressando em outras tabelas com essa chave, precisará atualizar também as outras tabelas, o que pode ser bastante prejudicial ao desempenho quando uma empresa cliente inteira altera seus e-mails (o que eu já vi acontecer).

HLGEM
fonte
47
+1 por mencionar o problema de atualização em cascata. É por isso que os amigos permitem que os amigos usem apenas chaves substitutas ;-).
precisa saber é o seguinte
10
ah, não gosto de dizer nada ... chaves substitutas também podem ser a fonte de problemas; Sim, o aplicativo será mais robusto para alterar as regras de negócios e / ou integridade, no entanto, as informações podem se perder um pouco mais facilmente e a identidade dos registros fica menos clara. então eu não recomendaria uma regra geral aqui ...
Desrazão
12
@onedaywhen e @jay, apenas porque você acha que deve ser único, não o torna único. E sim, marido e mulher podem ser clientes diferentes. Apenas porque você não se deparou com isso antes não significa que isso não vai acontecer. Eu me deparei com isso e acontece que é por isso que o email nunca deve ser considerado único, seja você o que pensa ou não. Esse é o tipo de requisito que você adia porque é inerentemente errado.
HLGEM
15
@HLGEM: Eu não quero entrar em uma discussão sem fim, mas você não pode dizer que uma chave proposta não é única com base em hipóteses sem conhecer o contexto. por exemplo, do ponto de vista da companhia telefônica, um número de telefone identifica exclusivamente um cliente, por definição. Sim, você pode dizer: "Mas e se houver duas ou três pessoas que possam responder quando você ligar para esse número?" Mas isso é irrelevante. Do ponto de vista da companhia telefônica, por definição, este é um cliente. (continuação ...)
Jay
14
(continuação) Da mesma forma, se você estiver construindo um sistema que se preocupa amplamente com as comunicações por email - talvez um sistema de envio de mensagens ou um sistema de encaminhamento de notificações -, é provável que, por definição, um endereço de email identifique exclusivamente um usuário. Se várias pessoas compartilharem esse endereço de email, isso é irrelevante. Eles são um único destino de mensagem, portanto, são um único usuário. "Usuário" e "cliente" não precisam ser sinônimos para "ser humano individual".
Jay
99

a chave primária deve ser única e constante

os endereços de email mudam como as estações do ano. Útil como chave secundária para pesquisa, mas é uma má escolha para a chave primária.

Steven A. Lowe
fonte
17
Uma propriedade de uma boa chave é que ela deve ser estável, mas NÃO necessariamente imutável.
precisa saber é o seguinte
5
@onedaywhen: Sim! Caso contrário, por que o SQL suportaria atualizações em cascata?
Bill Karwin
18
se você tiver escolha, escolha chaves constantes / imutáveis; menos trabalho para você no caminho; só porque o SQL suporta atualizações em cascata não significa que é sempre uma boa ideia!
Steven A. Lowe
7
@Incent Malgrat: "atualizações em cascata ... freia a normalização do banco de dados" - parece que você entendeu mal o conceito de normalização!
Onedaywhen
5
@Incent Malgrat: obrigado por confirmar que você realmente entendeu mal o conceito de normalização. "você não deve repetir a mesma informação em várias linhas" - você realmente quis dizer "informação" ?! Uma chave composta geralmente envolve valores repetidos em várias linhas. Para uma chave estrangeira, os valores são referenciados, e não "repetidos", grande diferença. Um domínio de coluna única com dois valores (por exemplo, 'Sim' e 'Não') terá os mesmos valores em várias linhas em uma tabela de referência se tiver três ou mais linhas. Isso é realmente básico!
precisa saber é o seguinte
64

Desvantagens de usar um endereço de email como chave primária:

  1. Mais devagar ao fazer junções.

  2. Qualquer outro registro com uma chave estrangeira publicada agora tem um valor maior, ocupando mais espaço em disco. (Dado o custo do espaço em disco hoje, esse provavelmente é um problema trivial, exceto na medida em que o registro agora leva mais tempo para ser lido. Consulte o item 1.)

  3. Um endereço de email pode mudar, o que força todos os registros que usam isso como uma chave estrangeira a serem atualizados. Como o endereço de email não muda com tanta frequência, o problema de desempenho é provavelmente menor. O maior problema é que você precisa garantir isso. Se você precisar escrever o código, isso é mais trabalhoso e apresenta a possibilidade de erros. Se o seu mecanismo de banco de dados suportar "em cascata de atualização", é um problema menor.

Vantagens de usar o endereço de email como chave primária:

  1. Você pode eliminar completamente algumas junções. Se tudo o que você precisa no "registro mestre" for o endereço de email, com uma chave inteira abstrata, será necessário fazer uma junção para recuperá-lo. Se a chave é o endereço de email, você já o possui e a associação é desnecessária. Se isso ajuda você depende de quantas vezes essa situação surge.

  2. Quando você está fazendo consultas ad hoc, é fácil para um ser humano ver qual registro mestre está sendo referenciado. Isso pode ser uma grande ajuda ao tentar rastrear problemas de dados.

  3. Você quase certamente precisará de um índice no endereço de e-mail, tornando-a a chave primária para eliminar um índice, melhorando assim o desempenho das inserções, pois agora elas têm apenas um índice para atualizar em vez de dois.

Na minha humilde opinião, não é um slam-dunk de qualquer maneira. Costumo preferir usar chaves naturais quando uma prática está disponível, porque elas são mais fáceis de trabalhar, e as desvantagens tendem a não ser muito importantes na maioria dos casos.

Jay
fonte
@Conrad: No entanto, ele ressalta que não é uma PITA se você tiver um mecanismo compatível com ON UPDATE CASCADE. Não é um problema nesse ponto em termos de código; o único problema real é a extensão da atualização e a largura da chave. O endereço de e-mail pode ser um pouco demais, mas uma ATUALIZAÇÃO DA CASCADE para um código de país de dois caracteres com PK não é grande coisa.
Matthew Wood
5
@ Matthew IMHO ainda é uma PITA. Por exemplo, suponha que quando você projetou a tabela de seu país, havia apenas duas tabelas que a referenciavam, nada demais. Mas com o tempo, tornaram-se 20 tabelas, cada uma com centenas de milhares de registros. Alguns com a referência, outros sem. Isso faz com que uma única gravação lógica acabe sendo dezenas de milhares de gravações, e não chega a todas as tabelas porque alguém esqueceu uma referência quando adicionou a tabela. Isso é exatamente o que aconteceu comigo em uma tabela de códigos de países com 2 caracteres.
Conrad Frix
@ Wood & Conrad: O pior caso é quando não há suporte a banco de dados embutido. Em seguida, você deve escrever um código para cada tabela com uma referência postada, e isso é apenas uma dor e uma porta para a entrada de bugs. Com as cascatas, você só precisa se lembrar de adicionar uma cláusula em cada tabela, não como essa. um grande negócio.
Jay
2
As vantagens 1 e 3 são otimizações prematuras, a vantagem 2 é um benefício muito menor e é completamente superada por qualquer ferramenta de consulta decente.
Ash
4
@ Ash: Há uma diferença entre "otimização" e "otimização prematura". Mas tudo bem, pelo mesmo raciocínio, todas as desvantagens que vi alguém mencionar são otimizações prematuras. Então onde é que isso deixa você? Quanto ao item 2, acho que digitar junções extras ao tentar fazer consultas ad hoc é um grande problema. Os registros geralmente têm várias chaves estrangeiras; portanto, você pode precisar de várias junções para obter dados compreensíveis. Se, por "ferramenta de consulta decente", você quer dizer um que descubra quais dados você deseja ver sem que você os informe e faça as junções magicamente para você, eu gostaria de ver como isso funciona.
Jay
12

Isso é muito ruim. Suponha que algum provedor de e-mail saia do negócio. Os usuários desejarão alterar seus emails. Se você usou o email como chave primária, todas as chaves estrangeiras dos usuários duplicarão esse email, dificultando a alteração ...

... e nem comecei a falar sobre considerações de desempenho.

Meriton
fonte
Como a alteração de endereços de email causaria duplicatas? A menos que o usuário A altere seu endereço de email e, em seguida, o usuário B altere seu email para ser o mesmo que o valor antigo do usuário A, e suas atualizações não serão feitas em sequência. Remotamente possível, eu acho.
Jay
2
Uma referência de chave estrangeira, por definição, contém o valor da chave primária da linha à qual se refere. Em outras palavras, ele duplica o valor da chave primária. (Portanto, a duplicação não é causada pela alteração do valor. Mas a alteração é mais difícil devido a essa duplicação e à restrição que a impõe).
meriton 27/09/10
5
+1 na linha "Suponha que algum provedor de e-mail falhe".
Reddy
Isso não é um problema. Existe uma cascata de chave estrangeira para resolver esse problema. Se um usuário alterar seu email, a alteração será transmitida em cascata a todas as tabelas usando-o como chave estrangeira.
Rafa
1
@rafa, garanto que, se você usar atualizações em cascata e um provedor inteiro sair do negócio ou alterar seu nome (o Yahoo.com se torna HooYa.com), seu banco de dados será bloqueado para todos os usuários por horas e talvez dias enquanto isso estiver em cascata. através do sistema. É um problema muito válido (e uma razão pela qual é uma má idéia para usar em cascata atualizações se você tiver qualquer quantidade significativa de dados ea chave é provável que a mudança.)
HLGEM
12

Não sei se isso pode ser um problema na sua configuração, mas, dependendo do seu RDBMS, os valores de uma coluna podem fazer distinção entre maiúsculas e minúsculas . Os documentos do PostgreSQL dizem: "Se você declarar uma coluna como UNIQUE ou PRIMARY KEY, o índice gerado implicitamente faz distinção entre maiúsculas e minúsculas". Em outras palavras, se você aceitar a entrada do usuário para uma pesquisa em uma tabela com email como chave primária e o usuário fornecer "[email protected]", você não encontrará "[email protected]".

xlttj
fonte
7
Vale mencionar, neste contexto, que [email protected] e [email protected] podem ser a mesma caixa de correio ou podem ser caixas de correio diferentes e você não tem como dizer - não há nada na especificação para dizer se a parte local é maiúscula e minúscula. sensível.
telent 29/09/10
Esse é mais um problema geral com a imposição exclusiva de endereços de email, e não se eles devem ser usados ​​como chaves primárias - o mesmo problema existe de qualquer maneira. +1 porque ainda é um ponto muito útil
11

Parece que ninguém mencionou um possível problema: os endereços de email podem ser considerados privados. Se o endereço de e-mail for a chave principal, o URL de uma página de perfil provavelmente será semelhante a ..../Users/[email protected]. E se você não quiser expor o endereço de email do usuário? Você precisaria encontrar outra maneira de identificar o usuário, possivelmente por um valor inteiro único para criar URLs ..../Users/1. Você acabaria com um valor inteiro único, afinal.

Simen Echholt
fonte
9

No nível lógico , o email é a chave natural. No nível físico , desde que você esteja usando um banco de dados relacional, a chave natural não se encaixa bem na chave primária. O motivo é principalmente os problemas de desempenho mencionados por outros.

Por esse motivo, o design pode ser adaptado. A chave natural se torna a chave alternativa (UNIQUE, NOT NULL) e você usa uma chave substituta / artificial / técnica como chave primária, o que pode ser um incremento automático no seu caso.

systempuntoout perguntou,

E se alguém quiser alterar seu endereço de email? Você vai mudar todas as chaves estrangeiras também?

É para isso que serve a cascata .

Outro motivo para usar uma chave substituta numérica como chave primária está relacionado a como a indexação funciona em sua plataforma. No InnoDB do MySQL, por exemplo, todos os índices em uma tabela têm a chave primária pendente, então você deseja que o PK seja o menor possível (por questões de velocidade e tamanho). Também relacionado a isso, o InnoDB é mais rápido quando a chave primária é armazenada em sequência, e uma string não ajudaria lá.

Outra coisa a ser levada em consideração ao usar uma string como chave alternativa é que o uso de um hash da string que você deseja pode ser mais rápido, ignorando coisas como letras maiúsculas e minúsculas. (Na verdade, cheguei aqui enquanto procurava uma referência para confirmar o que acabei de dizer; ainda estou procurando ...)

Rafa
fonte
5

Sim, é uma chave primária ruim porque seus usuários desejam atualizar seus endereços de email.

Bryan Legend
fonte
1
Pensei em apontar que agora temos cascata este não é um problema
malhal
4

Sim, é melhor se você usar um número inteiro. você também pode definir sua coluna de email como restrição exclusiva.

como isso:

CREATE TABLE myTable(
    id integer primary key,
    email text UNIQUE
);
ibram
fonte
8
Por que é "melhor"? Alguma razão ou fonte?
Sjoerd
20
Você pode elaborar sobre isso?
Sjoerd
3

Outro motivo pelo qual a chave primária inteira é melhor é quando você se refere ao endereço de email na tabela diferente. Se o endereço em si for uma chave primária, em outra tabela você deverá usá-lo como chave. Então você armazena endereços de e-mail várias vezes.

klew
fonte
3

Eu não estou muito familiarizado com o postgres. Chaves primárias é um grande tópico. Eu já vi algumas excelentes perguntas e respostas neste site (stackoverflow.com).

Eu acho que você pode ter um melhor desempenho por ter uma chave primária numérica e usar um ÍNDICE UNIQUE na coluna de email. Os emails tendem a variar em tamanho e podem não ser adequados para o índice de chave primária.

algumas leituras aqui e aqui.

Saif Khan
fonte
3

Pessoalmente, não uso nenhuma informação para chave primária ao projetar o banco de dados, porque é muito provável que eu precise alterar essas informações posteriormente. A única razão pela qual eu forneço a chave primária é que é conveniente fazer a maioria das operações SQL do lado do cliente, e minha opção por isso sempre foi o tipo inteiro de incremento automático.

tia
fonte
2

Seu colega está certo: use um número inteiro com aumento automático para sua chave primária.

Você pode implementar a exclusividade de email no nível do aplicativo ou marcar sua coluna de endereço de email como exclusiva e adicionar um índice nessa coluna.

Adicionar o campo como exclusivo custará uma comparação de cadeias apenas ao inserir nessa tabela, e não ao executar junções e verificações de restrição de chave estrangeira.

Obviamente, você deve observar que adicionar restrições ao seu aplicativo no nível do banco de dados pode tornar seu aplicativo inflexível. Sempre dê a devida consideração antes de tornar qualquer campo "exclusivo" ou "não nulo" apenas porque seu aplicativo precisa que ele seja exclusivo ou não esteja vazio.

jrharshath
fonte
1
"Sempre leve em devida consideração antes de implementar o requisito x, apenas porque seu aplicativo precisa do requisito x." - o pior conselho que já li há algum tempo.
precisa saber é o seguinte
Não estou convencido pelo seu "argumento" - na vida real, muitas vezes existem situações em que alguns dados essenciais (por exemplo, um número de telefone) não estarão disponíveis imediatamente. Se esse campo estiver marcado como NOT NULL em um banco de dados, será necessário que os usuários poluam os dados com campos fictícios (como 123), em vez de deixá-los vazios. Seria mais prático permitir que o aplicativo lida com as restrições (e, nesse caso, o aplicativo pode sinalizar um campo vazio como um item de ação).
Jrharshath
5
Concordo que a definição de um campo "não nulo" deve ser feita com cautela. Requisitos como "sempre precisamos do número de telefone do cliente" devem ser considerados com cuidado. Às vezes, não seria desejável criar um registro de cliente, mesmo que não soubéssemos o número de telefone no momento e voltar e buscá-lo mais tarde? Mas "este campo deve ser exclusivo" é uma categoria diferente. Não consigo imaginar dizendo: "Não há problema em dois funcionários terem o mesmo número de previdência social, descobriremos mais tarde". Como você corrige os dados?
Jay
1
Be Wolves: Eu conheci uma mulher uma vez que não tinha seu próprio número de telefone. O que fazes, então?
David Thornley
@DavidThornley Parece que você deveria se exercitar mais, ou talvez adaptar um comportamento mais amigável.
Philip Schiff
2

Use um GUID como chave primária ... para que você possa gerá-lo a partir do seu programa quando fizer um INSERT e não precisará obter uma resposta do servidor para descobrir qual é a chave primária. Também será exclusivo entre tabelas e bancos de dados e você não precisa se preocupar com o que acontece se você truncar a tabela algum dia e o incremento automático for redefinido para 1.

JoelFan
fonte
2
A menos que você se importe pouco ou nada com desempenho, use um GUID. É falta de nenhum # 1 se você está construindo um sistema que terá de escala
Micah
Não ... consulte davybrion.com/blog/2009/05/…
JoelFan
3
Disse na verdadeira moda de beber em Microsoft-Kool-Aid!
Gary Chambers
2

Sei que é um pouco tardio, mas gostaria de acrescentar que as pessoas abandonam as contas de email e os provedores de serviços recuperam o endereço, permitindo que outra pessoa o utilize.

Como o @HLGEM apontou, "[email protected] pode facilmente pertencer a John Smith um ano e Julia Smith dois anos depois". nesse caso, caso John Smith deseje seu serviço, você deve recusar-se a usar o endereço de e-mail dele ou excluir todos os seus registros pertencentes a Julia Smith.

Se você precisar excluir registros e eles estiverem relacionados ao histórico financeiro da empresa, dependendo da legislação local, você poderá se encontrar em água quente.

Portanto, eu nunca usaria dados como endereços de e-mail, chapas de matrícula etc. como chaves primárias, porque não importa o quão exclusivos eles pareçam estar fora de seu controle e pode oferecer alguns desafios interessantes com os quais você pode não ter tempo para lidar.

Robert
fonte
2

Pode ser necessário considerar qualquer legislação de regulamentação de dados aplicável. O email é uma informação pessoal e, se seus usuários são cidadãos da UE, por exemplo, no GDPR, eles podem instruí-lo a excluir suas informações dos seus registros (lembre-se de que isso se aplica independentemente do país em que você se baseia).

Se você precisar manter o próprio registro no banco de dados por integridade referencial ou por razões históricas, como auditoria, o uso de uma chave substituta permitiria anular apenas todos os campos de dados pessoais. Obviamente, isso não é tão fácil se seus dados pessoais forem a chave primária

Stuart Parker
fonte
1

você pode melhorar o desempenho usando a chave primária inteira.

xport
fonte
1

você deve usar uma chave primária inteira. se você precisa que a coluna de email seja exclusiva, por que simplesmente não define um índice exclusivo nessa coluna?

oezi
fonte
1

Se você tiver um valor não int como chave primária, as inserções e recuperações serão muito lentas em dados grandes.

Amareswar
fonte
1
Não, as inserções serão mais lentas , porque você precisa de dois índices exclusivos: um na chave primária gerada e outro no endereço de email.
a_horse_with_no_name
1

chave primária deve ser escolhido um atributo estático. Como os endereços de email não são estáticos e podem ser compartilhados por vários candidatos, não é uma boa ideia usá-los como chave primária. Além disso, os endereços de e-mail são cadeias geralmente com um determinado comprimento que pode ser maior que o ID único que gostaríamos de usar [len (endereço_de_ email)> len (nome_id)], por isso exigiria mais espaço e, pior ainda, eles serão armazenados várias vezes como chave estrangeira . E, consequentemente, levará a degradar o desempenho.

user2719152
fonte
0

Depende da mesa. Se as linhas na sua tabela representam endereços de email, o email é o melhor ID. Caso contrário, o email não é um bom ID.

Lajos Arpad
fonte
0

Se for apenas uma questão de exigir que o email seja exclusivo, basta criar um índice exclusivo com essa coluna.

Micah
fonte
0

O email é um bom candidato a índice exclusivo, mas não para a chave primária; se for uma chave primária, você não poderá alterar o endereço de email do contato, por exemplo. Acho que suas consultas de junção também serão mais lentas.

Chocolim
fonte
0

não use o endereço de email como chave primária, mantenha o email como único, mas não o use como chave primária, use o ID do usuário ou nome de usuário como chave primária

Nikki
fonte