Nos meus bancos de dados, tenho o hábito de ter uma chave primária inteira de incremento automático com o nome id
de todas as tabelas que faço, para ter uma pesquisa exclusiva para qualquer linha específica.
Isso é considerado uma má ideia? Existem desvantagens em fazê-lo dessa maneira? Às vezes, tenho vários índices, como id, profile_id, subscriptions
onde id
está o identificador exclusivo, profile_id
links para o exterior id
de uma Profile
tabela etc.
Ou há cenários em que você não deseja adicionar esse campo?
t
e o ativo 120 no momentot + 60
. Se você pode ver esses dois IDs (100 e 120) de forma não ofuscada, agora conhece o número total de ativos que existem, bem como aproximadamente a taxa na qual eles são criados. Isso é vazamento de informações. Isto não é puramente hipotético.Respostas:
Nunca é uma má idéia ter um identificador de linha exclusivo garantido. Acho que não devo dizer nunca - mas vamos com a grande maioria das vezes que é uma boa ideia.
As desvantagens potenciais teóricas incluem um índice extra para manter e espaço de armazenamento extra usado. Isso nunca foi motivo suficiente para eu não usar um.
fonte
TableName.id
ao contrárioTableName.TableName_id
, porque a que mais issoid
se refere? Se eu tiver outro campo de identificação na tabela, prefixo-o com um nome de tabela se estiver se referindo a alguma outra tabela.WITHOUT ROWID
tabelas (com explícitoPRIMARY KEY
) como uma otimização. Mas, caso contrário, umaINTEGER PRIMARY KEY
coluna é um alias para o rowid.Eu discordo de todas as respostas anteriores. Há muitas razões pelas quais é uma má idéia adicionar um campo de incremento automático em todas as tabelas.
Se você possui uma tabela na qual não há chaves óbvias, um campo de incremento automático parece uma boa ideia. Afinal, você não quer
select * from blog where body = '[10000 character string]'
. Você prefereselect * from blog where id = 42
. Eu diria que, na maioria desses casos, o que você realmente deseja é um identificador único; não é um identificador exclusivo sequencial. Você provavelmente deseja usar um identificador universalmente exclusivo.Existem funções na maioria dos bancos de dados para gerar identificadores únicos aleatórios (
uuid
no mysql, postgres.newid
No mssql). Isso permite gerar dados em vários bancos de dados, em máquinas diferentes, a qualquer momento, sem conexão de rede entre eles, e ainda mesclar dados com zero conflitos. Isso permite que você configure mais facilmente vários servidores e até data centers, como por exemplo, com microsserviços.Isso também evita que os invasores adivinhem os URLs das páginas às quais eles não deveriam ter acesso. Se há um
https://example.com/user/1263
, provavelmente existehttps://example.com/user/1262
também. Isso pode permitir a automação de uma exploração de segurança na página de perfil do usuário.Também existem muitos casos em que uma coluna de uuid é inútil ou até prejudicial. Digamos que você tenha uma rede social. Há uma
users
mesa e umafriends
mesa. A tabela de amigos contém duas colunas de ID do usuário e um campo de incremento automático. Você quer3
ser amigo e5
inserir3,5
no banco de dados. O banco de dados adiciona um ID de incremento automático e armazena1,3,5
. De alguma forma, o usuário3
clica no botão "adicionar amigo" novamente. Você insere3,5
no banco de dados novamente, o banco de dados adiciona um ID de incremento automático e insere2,3,5
. Mas agora3
e5
são amigos um do outro duas vezes! Isso é um desperdício de espaço e, se você pensar sobre isso, também é a coluna de incremento automático. Tudo o que você precisa para ver sea
eb
são amigos é selecionar para a linha com esses dois valores. Eles são, juntos, um identificador de linha exclusivo. (Você provavelmente escreveria alguma lógica para ter certeza3,5
e5,3
deduplicação.)Ainda existem casos em que os IDs seqüenciais podem ser úteis, como na criação de um encurtador de URL, mas principalmente (e mesmo com o encurtador de URL) um ID exclusivo gerado aleatoriamente é o que você realmente deseja usar.
TL; DR: use UUIDs em vez de incremento automático, se você ainda não tem uma maneira única de identificar cada linha.
fonte
As teclas auto-incrementais têm principalmente vantagens.
Mas algumas desvantagens possíveis podem ser:
Aqui está uma seção de artigo da Wikipedia sobre as desvantagens das chaves substitutas.
fonte
Apenas para ser contrário, não, você NÃO precisa sempre ter um AutoInc PK numérico.
Se você analisar seus dados cuidadosamente, geralmente identifica chaves naturais nos dados. Geralmente, esse é o caso quando os dados têm um significado intrínseco para os negócios. Às vezes, as PKs são artefatos de sistemas antigos que os usuários corporativos utilizam como um segundo idioma para descrever os atributos de seu sistema. Vi números de VIN de veículos usados como chave primária de uma tabela "Veículo" em um sistema de gerenciamento de frotas, por exemplo.
Seja como for, se você já possui um identificador exclusivo, use-o. Não crie uma segunda chave primária sem sentido; é um desperdício e pode causar erros.
Às vezes, você pode usar um AutoInc PK para gerar um valor significativo para o cliente, por exemplo, números de política. Definir o valor inicial para algo sensato e aplicar regras de negócios sobre zeros à esquerda, etc. Essa é provavelmente uma abordagem do "melhor dos dois mundos".
Quando você tiver um pequeno número de valores relativamente estáticos, use valores que façam sentido para o usuário do sistema. Por que usar 1,2,3 quando você pode usar L, C, H, onde L, H e C representam Vida, Carro e Lar em um contexto de "Tipo de Política" de seguro ou, voltando ao exemplo do VIN, que tal usar "TO "para a Toyota? Todos os carros da Toyata têm um VIN que inicia o "TO". É uma coisa a menos para os usuários lembrarem, torna menos provável a introdução de erros de programação e do usuário e pode até ser um substituto utilizável para uma descrição completa nos relatórios de gerenciamento, tornando os relatórios mais simples. para escrever e talvez mais rápido para gerar.
Um desenvolvimento adicional disso provavelmente é "uma ponte longe demais" e geralmente não a recomendo, mas estou incluindo-a por completo e você pode achar um bom uso para ela. Ou seja, use a Descrição como chave primária. Para dados que mudam rapidamente, isso é uma abominação. Para dados muito estáticos relatados em Todo o tempo , talvez não. Apenas mencionando, para que fique lá como uma possibilidade.
Eu uso AutoInc PKs, apenas envolvo meu cérebro e procuro melhores alternativas primeiro. A arte do design de banco de dados está criando algo significativo que pode ser consultado rapidamente. Ter muitas junções dificulta isso.
EDIT Outro caso crucial em que você não precisa de uma PK gerada automaticamente é o caso de tabelas que representam a interseção de duas outras tabelas. Para manter a analogia do carro, um carro tem 0..n acessórios, cada acessório pode ser encontrado em muitos carros. Portanto, para representar isso, você cria uma tabela Car_Accessory contendo as PKs de carro e acessório e outras informações relevantes sobre o link Datas etc.
O que você normalmente não precisa é de um AutoInc PK nesta tabela - ele só será acessado através do carro "diga-me quais são os acessórios deste carro" ou no acessório "diga-lhes quais carros têm este acessório"
fonte
Don't create a second, meaningless primary key; it's wasteful and may cause errors.
No entanto, se a maneira como você estabelece a exclusividade de um registro é uma combinação de 6 colunas, a junção das 6 o tempo todo é muito propensa a erros. Os dados naturalmente têm uma PK, mas é melhor usar umaid
coluna e uma restrição exclusiva nessas 6 colunas.Muitas tabelas já possuem um ID exclusivo natural. Não adicione outra coluna de ID exclusiva (incremento automático ou outro) nessas tabelas. Use o ID exclusivo natural. Se você adicionar outro ID exclusivo, terá essencialmente uma redundância (duplicação ou dependência) em seus dados. Isso vai contra os princípios da normalização. Um ID exclusivo depende do outro para precisão. Isso significa que eles devem ser mantidos perfeitamente sincronizados o tempo todo em todos os sistemas que gerenciam essas linhas. É apenas mais uma fragilidade na integridade dos dados que você realmente não deseja gerenciar e validar a longo prazo.
Atualmente, a maioria das tabelas atualmente não precisa do aumento de desempenho muito menor que uma coluna de ID exclusiva adicional daria (e às vezes isso prejudica o desempenho). Como regra geral em TI, evite redundâncias como a praga! Resista a todos os lugares que lhe forem sugeridos. É anátema. E preste atenção na citação. Tudo deve ser o mais simples possível, mas não mais simples. Não tenha dois IDs únicos onde um será suficiente, mesmo que o natural pareça menos organizado.
fonte
Em sistemas maiores, o ID é impulsionador da consistência; use-o quase em qualquer lugar. Nesse contexto, chaves primárias individuais NÃO são recomendadas, elas são caras na linha de fundo (leia o porquê).
Toda regra tem uma exceção, portanto, talvez você não precise do ID de incremento automático inteiro nas tabelas temporárias usadas para exportação / importação e em tabelas unidirecionais ou temporárias semelhantes. Você também prefere GUIDs em vez de IDs em sistemas distribuídos.
Muitas respostas aqui sugerem que a chave exclusiva existente deve ser usada. Bem, mesmo que tenha 150 caracteres? Acho que não.
Agora meu ponto principal:
Parece que os oponentes do ID inteiro de incremento automático estão falando sobre pequenos bancos de dados com até 20 tabelas. Lá eles podem pagar uma abordagem individual para cada tabela.
MAS, uma vez que você tenha um ERP com mais de 400 tabelas, ter um ID de incremento automático inteiro em qualquer lugar (exceto os casos mencionados acima) faz muito sentido. Você não confia em outros campos exclusivos, mesmo que estejam presentes e protegidos por exclusividade.
JOIN
tabela, sem precisar verificar quais são as chaves.Em sistemas maiores, pode valer a pena ignorar os benefícios menores dessas chaves primárias individuais e usar consistentemente o ID de incremento automático automático na maioria dos casos. O uso de campos exclusivos existentes como chaves primárias talvez economize alguns bytes por registro, mas o armazenamento adicional ou o tempo de indexação não causam problemas nos mecanismos de banco de dados atuais. Na verdade, você está perdendo muito mais dinheiro e recursos com o tempo perdido dos desenvolvedores / mantenedores. O software de hoje deve ser otimizado para o tempo e o esforço dos programadores - que abordagem com IDs consistentes é muito melhor.
fonte
Não é uma boa prática para projetos supérfluos. Ou seja, não é uma boa prática sempre ter um incremento automático na chave primária quando não for necessário.
Vamos ver um exemplo em que não é necessário.
Você tem uma tabela para artigos - esta possui uma chave primária int
id
e uma coluna varchar denominadatitle
.Você também tem uma tabela cheia de categorias de artigos -
id
chave primária int, varcharname
.Uma linha da tabela Artigos tem um
id
de 5 e umtitle
"Como cozinhar ganso com manteiga". Você deseja vincular esse artigo às seguintes linhas da tabela Categorias: "Fowl" ( identificação : 20), "Ganso" ( identificação : 12), "Culinária" ( identificação : 2), "Manteiga" (identificação: 9) .Agora, você tem 2 tabelas: artigos e categorias. Como você cria o relacionamento entre os dois?
Você pode ter uma tabela com 3 colunas: id (chave primária), article_id (chave estrangeira), category_id (chave estrangeira). Mas agora você tem algo como:
Uma solução melhor é ter uma chave primária composta de 2 colunas.
Isso pode ser feito fazendo:
Outro motivo para não usar um número inteiro de incremento automático é se você estiver usando UUIDs para sua chave primária.
Os UUIDs são, por definição, únicos, o que realiza o mesmo que o uso de números inteiros únicos. Eles também têm seus próprios benefícios adicionais (e contras) sobre números inteiros. Por exemplo, com um UUID, você sabe que a string exclusiva à qual você está se referindo aponta para um registro de dados específico; isso é útil nos casos em que você não possui um banco de dados central ou onde os aplicativos têm a capacidade de criar registros de dados offline (depois carregue-os no banco de dados posteriormente).
No final, você não precisa pensar nas chaves primárias como algo. Você precisa pensar neles como a função que desempenham. Por que você precisa de chaves primárias? Ser capaz de identificar exclusivamente conjuntos específicos de dados de uma tabela usando um campo que não será alterado no futuro. Você precisa de uma coluna específica chamada
id
para fazer isso ou pode basear essa identificação exclusiva em outros dados (imutáveis)?fonte
Certo.
Primeiro de tudo, existem bancos de dados que não possuem incrementos automáticos (por exemplo, Oracle, que certamente não é um dos menores concorrentes). Essa deve ser a primeira indicação de que nem todo mundo gosta ou precisa deles.
Mais importante, pense sobre o que realmente é o ID - é a chave principal para seus dados. Se você possui uma tabela com uma chave primária diferente, não precisa de um ID e não deve ter um. Por exemplo, uma tabela
(EMPLOYEE_ID, TEAM_ID)
(onde cada funcionário pode estar em várias equipes simultaneamente) possui uma chave primária claramente definida, consistindo nesses dois IDs. Adicionar umaID
coluna de incremento automático , que também é uma chave primária para esta tabela, não faria sentido. Agora você está carregando duas chaves primárias e a primeira palavra em "chave primária" deve dar uma dica de que você realmente deve ter apenas uma.fonte
Normalmente, uso uma coluna "identidade" (número inteiro com aumento automático) ao definir novas tabelas para dados "de longa duração" (registros que espero inserir uma vez e permanecer indefinidamente, mesmo que eles acabem "excluídos logicamente" definindo um campo de bit )
Existem algumas situações em que não consigo usá-las, a maioria delas se resume a cenários em que uma tabela em uma instância do banco de dados não pode ser a fonte autorizada para novos valores de ID:
Existem soluções alternativas que permitem o uso de colunas de identidade nessas situações, como eu já mencionei, mas na maioria delas, a atualização da coluna inteira de identidade para um GUID é mais simples e resolve o problema mais completamente.
fonte
ID, ID_M, ID_N
) devido à anexação de propriedades às instâncias da sua relação M: N.Uma chave primária de incremento automático (identidade) é uma boa idéia, exceto para observar que não faz sentido fora do contexto do banco de dados e de clientes imediatos desse banco de dados. Por exemplo, se você transferir e armazenar alguns dados em outro banco de dados, e depois gravar dados diferentes nas duas tabelas, os IDs divergirão - ou seja, dados com um ID de 42 em um banco de dados não corresponderão necessariamente aos dados com um id de 42 no outro.
Dado isso, se ainda for necessário identificar linhas exclusivamente fora do banco de dados (e é frequentemente), você deverá ter uma chave diferente para esse fim. Uma chave de negócios cuidadosamente selecionada serve, mas muitas vezes você acaba na posição de um grande número de colunas necessárias para garantir a exclusividade. Outra técnica é ter uma coluna de ID como uma chave primária em cluster de incremento automático e outra coluna de identificador único (guid) como uma chave exclusiva não em cluster, com o objetivo de identificar exclusivamente a linha onde quer que ela exista no mundo. O motivo de você ainda ter uma chave de incremento automático nesse caso é porque é mais eficiente agrupar e indexar a chave de incremento automático do que fazer o mesmo em um guia.
Um caso em que você pode não querer uma chave de incremento automático seria uma tabela muitos para muitos, onde a chave primária é um composto das colunas de ID de duas outras tabelas (você ainda pode ter uma chave de incremento automático aqui, mas eu não entendo o motivo disso).
Outra pergunta é o tipo de dados da chave incrementada automaticamente. O uso de um Int32 fornece um intervalo grande, mas relativamente limitado de valores. Pessoalmente, uso frequentemente colunas bigint para o ID, para praticamente nunca precisar me preocupar com a falta de valores.
fonte
Como outras pessoas defenderam uma chave primária de incremento, farei uma para uma GUID:
Editar: ponto duplicado
fonte
Como princípio do bom design, todas as tabelas devem ter uma maneira confiável de identificar exclusivamente uma linha. Embora seja para isso que serve uma chave primária, ela nem sempre exige a existência de uma chave primária. Adicionar uma chave primária a todas as tabelas não é uma prática ruim, pois fornece identificação de linha exclusiva, mas pode ser desnecessário.
Para manter relacionamentos confiáveis entre as linhas de duas ou mais tabelas, é necessário fazê-lo através de chaves estrangeiras, daí a necessidade de chaves primárias em pelo menos algumas tabelas. A adição de uma chave primária a todas as tabelas facilita a extensão do design do banco de dados quando chega a hora de adicionar novas tabelas ou relacionamentos aos dados existentes. Planejar com antecedência é sempre uma coisa boa.
Como princípio básico (regra difícil, talvez), o valor de uma chave primária nunca deve mudar ao longo da vida útil de sua linha. É aconselhável supor que todos os dados corporativos consecutivos estão sujeitos a alterações ao longo da vida útil; portanto, quaisquer dados corporativos serão um candidato ruim para uma chave primária. É por isso que algo abstrato como um número inteiro auto-incrementado geralmente é uma boa idéia. No entanto, números inteiros auto-incrementados têm suas limitações.
Se seus dados tiverem apenas uma vida útil no seu banco de dados, números inteiros auto-incrementados são bons. Mas, como já foi mencionado em outras respostas, se você quiser que seus dados sejam compartilhados, sincronizados ou tenham uma vida fora do banco de dados, números inteiros incrementados automaticamente produzem chaves primárias ruins. Uma melhor escolha será um guia (também conhecido como "id universalmente exclusivo" do uuid).
fonte
A pergunta e muitas das respostas perdem o ponto importante de que todas as chaves naturais de cada tabela residem apenas no esquema lógico do banco de dados e todas as chaves substitutas de cada tabela residem apenas no esquema físico do banco de dados. outras respostas discutem apenas os benefícios relativos de chaves substitutas de número inteiro versus GUID, sem discutir os motivos pelos quais as chaves substitutas são usadas corretamente e quando.
BTW: evitemos o uso da chave primária do termo mal definido e impreciso . É um artefato de modelos de dados pré-relacionais que primeiro foi cooptado (imprudentemente) no modelo relacional e depois cooptado de volta ao domínio físico por vários fornecedores de RDBMS. Seu uso serve apenas para confundir a semântica.
Observe no modelo relacional que, para que o esquema lógico do banco de dados esteja na primeira forma normal , toda tabela deve ter um conjunto de campos visível ao usuário, conhecido como chave natural, que identifique exclusivamente cada linha da tabela. Na maioria dos casos, essa chave natural é facilmente identificada, mas, ocasionalmente, é preciso construir, seja como campo de desempate ou de outra forma. No entanto, essa chave construída ainda é sempre visível ao usuário e, portanto, sempre reside no esquema lógico do banco de dados.
Por outro lado, qualquer chave substituta em uma tabela reside puramente no esquema físico do banco de dados (e, portanto, sempre deve, por razões de segurança e manutenção da integridade do banco de dados, ser totalmente invisível para os usuários do banco de dados). O único motivo para a introdução de uma chave substituta é tratar de problemas de desempenho na manutenção física e no uso do banco de dados; sejam junções, replicação, várias fontes de hardware para dados ou outras.
Como o único motivo para a introdução de uma chave substituta é o desempenho, suponhamos que desejamos que ela tenha desempenho. Se o problema de desempenho em questão for unido, queremos necessariamente tornar nossa chave substituta o mais estreita possível (sem atrapalhar o hardware, portanto, números e bytes curtos geralmente ficam fora). O desempenho da junção depende da altura mínima do índice; portanto, um número inteiro de 4 bytes é uma solução natural. Se o seu problema de desempenho for a taxa de inserção, um número inteiro de 4 bytes também poderá ser uma solução natural (dependendo dos componentes internos do RDBMS). Se o problema de desempenho de uma tabela for replicação ou várias fontes de dados, além de alguma outra tecnologia de chave substituta , seja um GUID ou uma chave de duas partes (ID do host + número inteiro) pode ser mais adequado. Pessoalmente, não sou o favorito dos GUIDs, mas eles são convenientes.
Para resumir, nem todas as tabelas exigirão uma chave substituta (de qualquer tipo); elas devem ser usadas somente quando consideradas necessárias para o desempenho da tabela em consideração. Independentemente de qual tecnologia- chave substituta comum você preferir, pense cuidadosamente nas necessidades reais da tabela antes de fazer uma escolha; alterar a opção de tecnologia de chave substituta para uma tabela será um trabalho exaustivo. Documente a métrica de desempenho principal da sua tabela para que seus sucessores entendam as escolhas feitas.
Casos especiais
Se seus requisitos de negócios exigirem uma numeração seqüencial de transações para fins de auditoria (ou outros) além desse campo, não será uma chave substituta; é uma chave natural (com requisitos extras). Na documentação, um número inteiro com auto incremento gera apenas chaves substitutas ; portanto, encontre outro mecanismo para gerá-lo. Obviamente, será necessário algum tipo de monitor e, se você estiver fornecendo suas transações de vários sites, um site será especial , por ser o site host designado para o monitor.
Se sua tabela nunca terá mais do que cem linhas, a altura do índice será irrelevante; todo acesso será feito por uma varredura de tabela. No entanto, as comparações de seqüências de caracteres em seqüências longas ainda serão muito mais caras que a comparação de um número inteiro de 4 bytes e mais caras que a comparação de um GUID.
Uma tabela de valores de código digitados por um campo de código char (4) deve ter o mesmo desempenho que um com um número inteiro de 4 bytes. Embora não tenha prova disso, uso a suposição com frequência e nunca tive motivos para lamentá-la.
fonte
Não só não é uma boa prática, como também é descrito como um antipadrão no livro SQL Antipatterns de Bill Karwin.
Nem toda tabela precisa de uma pseudo-chave - uma chave primária com um valor arbitrário, não algo que tenha valor semântico para o modelo - e não há razão para sempre chamá-lo
id
.fonte
Isso é bastante universal - caso contrário, você precisaria validar que a chave é realmente única. Isso seria feito observando todas as outras chaves ... que consumiriam tempo. Ter uma chave incremental fica caro quando seu número de registro se aproxima do valor de estouro de chave.
Eu costumo tornar os ponteiros nomes de campo mais óbvios, como
ref_{table}
idéias semelhantes.Se não for necessário apontar externamente para um registro, você não precisará de um ID.
fonte
unsigned int
o tipo de campo, caso contrário, o limite é metade desse número.Eu não diria que isso sempre deve ser feito. Eu tenho uma tabela aqui sem chave única - e ela não precisa de uma. É um log de auditoria. Nunca haverá uma atualização; as consultas retornarão todas as alterações ao que está sendo registrado, mas é o melhor que pode ser feito razoavelmente; é necessário que um ser humano defina uma alteração incorreta. (Se o código pudesse ter desaprovado em primeiro lugar!)
fonte
Um contador de incremento automático para uma chave primária não é uma boa ideia. Isso ocorre porque você precisa voltar ao banco de dados para encontrar a próxima chave e aumentar em uma antes de inserir seus dados.
Dito isto, eu usaria geralmente o que o banco de dados pode fornecer para a chave primária, em vez de tê-la como parte do aplicativo.
Ao permitir que o banco de dados o forneça nativamente, você pode garantir que a chave seja única para o que precisa.
Obviamente, nem todos os bancos de dados o suportam. Nesse caso, eu geralmente uso uma tabela que armazena os principais depósitos e os intervalos altos e baixos gerenciados no aplicativo. Essa é a solução de melhor desempenho que encontro porque você obtém um intervalo de 10000 números e os incrementa automaticamente na instância do aplicativo. Outra instância do aplicativo pode pegar outro intervalo de números para trabalhar. Você precisa de uma primitiva de chave primária suficientemente grande, como um comprimento de 64 bits.
UUIDs que não uso como chaves primárias, porque o custo de construí-las e armazená-las é muito mais alto do que incrementar um valor longo por um. Os UUIDs ainda lidam com o paradoxo do aniversário, na medida em que uma duplicata pode teoricamente surgir.
fonte