Por que as pessoas recomendam não usar o nome "Id" para uma coluna de identidade?

68

Fui ensinado a não usar o nome Idda coluna de identidade de minhas tabelas, mas ultimamente apenas o uso de qualquer maneira, porque é simples, curto e muito descritivo sobre o que realmente são os dados.

Já vi pessoas sugerindo prefixar Ido nome da tabela, mas isso parece funcionar mais para a pessoa que escreve as consultas SQL (ou o programador, se você estiver usando um ORM como o Entity Framework), principalmente em nomes de tabela mais longos, como CustomerProductIdouAgencyGroupAssignementId

Um fornecedor terceirizado que contratamos para criar algo para nós realmente nomeou todas as suas colunas de identidade Identapenas para evitar o uso Id. No começo, pensei que eles fizeram isso porque Idera uma palavra-chave, mas, quando examinei, descobri que Idnão é uma palavra-chave no SQL Server 2005, que é o que estamos usando.

Então, por que as pessoas recomendam não usar o nome Idpara uma coluna de identidade?

Editar: para esclarecer, não estou perguntando qual convenção de nomenclatura usar, nem argumentos para usar uma convenção de nomenclatura sobre a outra. Eu só quero saber por que é recomendável não usar Idpara o nome da coluna de identidade.

Sou um único programador, não um dba, e para mim o banco de dados é apenas um local para armazenar meus dados. Como costumo criar aplicativos pequenos e normalmente uso um ORM para acesso a dados, é muito mais fácil trabalhar com um nome de campo comum para o campo de identidade. Quero saber o que estou perdendo ao fazer isso e se existem realmente boas razões para não fazer isso.

Rachel
fonte
10
BF bunfight aqui já: programmers.stackexchange.com/q/114728/5905 Vários de nós (leia-se: eu) fomos sugados por ele ...
gbn
Existe realmente uma regra contra o uso de "id" como o nome da coluna de identidade? O ActiveRecord, o ORM padrão para Ruby on Rails, faz exatamente isso por convenção. ar.rubyonrails.org
200_success
11
@ 200_success No nível do banco de dados, sim. Este é o site do banco de dados, não o site ORM;)
JNK
2
Além disso, para SQL Server especificamente, ver dba.stackexchange.com/questions/124655/... e, mais especificamente, connect.microsoft.com/SQLServer/feedback/details/2178150
Aaron Bertrand

Respostas:

46

O prefixo do nome da tabela tem boas razões.

Considerar:

TableA (id int identity, stringdata varchar(max))

TableB (id int identity, stringdata varchar(max))

Queremos DELETEde TableAregistros que existem nas duas tabelas. Fácil, basta fazer um INNER JOIN:

DELETE a
FROM 
  TableA A
INNER JOIN 
  TableB B
    ON b.id = B.id

.... e nós acabamos com tudo TableA. Inadvertidamente, comparamos o ID de B com ele próprio - todos os registros correspondiam e todos os registros eram excluídos.

Se os campos tivessem sido nomeados TableAIde TableBIdisso seria impossível ( Invalid field name TableAid in TableB).

Pessoalmente, não tenho nenhum problema em usar o nome idem uma tabela, mas é realmente uma prática melhor precedê-lo com o nome da tabela (ou nome da entidade, se as TableApessoas PeopleIdfuncionassem bem também) para evitar comparações acidentais com o campo errado e soprar alguma coisa.

Isso também torna muito óbvio a origem dos campos em consultas longas com muitos JOINs.

JNK
fonte
10
Portanto, é basicamente uma convenção de nomenclatura para proteger contra erros? Eu acho que usando begin transactione commit transactionseria melhor prática do que usar (IMO) um esquema de nomenclatura mais detestável
Rachel
13
@Rachel: é para 1. clareza 2. Evitar aliases de coluna desnecessários 3. Permitir que JOIN..USING 4. irritar os macacos PHP que trabalham em objetos únicos, não conjuntos
GBN
4
@ Rachel Se você não percebeu o erro ao escrever a consulta, e pouco antes de executá-la, é improvável que você a note antes de confirmar. Isso acontece, por que torná-lo mais provável?
21712 Andy
7
@ Andy sempre faço SELECTpara encontrar meus registros antes de executar o DELETEe, uma vez executada a instrução, sempre verifico se a contagem de linhas é o que eu espero antes de confirmar.
Rachel
5
@ Rachel Que bom que você tem algo que funciona para você. Você pode fazer todo mundo fazer isso?
21712 Andy
36

Principalmente é para impedir que as chaves estrangeiras se tornem uma dor tremenda. Digamos que você tenha duas tabelas: Customer e CustomerAddress. A chave primária para ambos é uma coluna chamada id, que é uma coluna de identidade (int).

Agora você precisa ter o ID do cliente referenciado no CustomerAddress. Como você não pode nomear o ID da coluna, obviamente, vá com customer_id.

Isso leva a alguns problemas. Primeiro, você deve se lembrar constantemente de quando chamar a coluna "id" e quando chamar "customer_id". E se você estragar tudo, isso leva ao segundo problema. Se você tiver uma consulta grande com cerca de uma dúzia de associações e não retornar nenhum dado, divirta-se jogando Where's Waldo e procurando esse erro de digitação:

ON c.id = ca.id

Opa, deveria ter sido ON c.id = ca.customer_id. Ou, melhor ainda, nomeie suas colunas de identidade de forma descritiva, para que assim seja ON c.customer_id = ca.customer_id. Então, se você acidentalmente usar o alias de tabela errado em algum lugar, customer_id não será uma coluna nessa tabela e você receberá um bom erro de compilação, em vez de resultados vazios e subsequentes estrabismo de código.

É verdade que há casos em que isso não ajuda, como se você precisar de vários relacionamentos de chave estrangeira de uma tabela para outra tabela única, mas nomear todas as chaves primárias "id" também não ajuda.

db2
fonte
27

Aqui está um resumo de todas as respostas sobre as vantagens obtidas na convenção de não usar um nome comum para todas as chaves primárias:

  • Menos erros, já que os campos de identidade não têm o mesmo nome

    Você não pode escrever por engano uma consulta que se associa ao B.Id = B.Idinvés de A.Id = B.Id, porque os campos de identidade nunca serão nomeados exatamente iguais.

  • Nomes de coluna mais claros.

    Se você olhar para uma coluna chamada CustomerId, você saberá imediatamente quais dados estão nessa coluna. Se o nome da coluna fosse algo genérico Id, será necessário conhecer o nome da tabela e saber quais dados a coluna contém.

  • Evita aliases desnecessários de coluna

    Agora você pode escrever a SELECT CustomerId, ProductIdpartir de uma consulta que se associa Customersa Products, em vez deSELECT Customer.Id as CustomerId, Products.Id as ProductId

  • Permite a JOIN..USINGsintaxe

    Você pode associar tabelas com a sintaxe Customer JOIN Products USING (CustomerId), em vez deCustomer JOIN Products ON Customer.Id = Products.Id

  • A chave é mais fácil de encontrar nas pesquisas

    Se você está procurando o campo de identidade de um cliente em uma solução grande, pesquisar CustomerIdé muito mais útil do que pesquisarId

Se você puder pensar em outras vantagens desta convenção de nomes, informe-me e adicionarei à lista.

Se você optar por usar nomes de colunas exclusivos ou idênticos para os campos de identidade, é com você, mas, independentemente do que você escolher, seja consistente :)

Rachel
fonte
12

Para copiar minha resposta da pergunta vinculada:

Há uma situação em que colar "ID" em todas as tabelas não é a melhor idéia: a USINGpalavra - chave, se for suportada. Nós o usamos frequentemente no MySQL.

Por exemplo, se você tiver fooTableuma coluna fooTableIde barTableuma chave estrangeira fooTableId, suas consultas poderão ser construídas da seguinte forma:

SELECT fooTableId, fooField1, barField2 FROM fooTable INNER JOIN barTable USING (fooTableId)

Ele não apenas salva a digitação, mas é muito mais legível em comparação com a alternativa:

SELECT fooTable.Id, fooField1, barField2 FROM fooTable INNER JOIN barTable ON (fooTable.Id = barTable.foTableId)
Izkata
fonte
9

Depois de normalizar um esquema de banco de dados para limitar a redundância, as tabelas são divididas em tabelas menores com relações estabelecidas (uma para uma, uma para muitas, muitas para muitas). No processo, campos únicos na tabela original podem aparecer em várias tabelas normalizadas.

Por exemplo, um banco de dados para um blog pode se parecer com isso em sua forma não normalizada, assumindo uma restrição exclusiva no Author_Nickname.

| Author_Nickname | Author_Email | Post_Title | Post_Body |
+-----------------+--------------+------------+-----------+
| dave            | dave@x.com   | Blah       | Bla bla   |
| dave            | dave@x.com   | Stuff      | I like    |
| sophie          | s@oph.ie     | Lorem      | Ipsum     |

A normalização produziria duas tabelas:

Autor:

| Author_Nickname | Author_Email |
+-----------------+--------------+
| dave            | dave@x.com   |
| sophie          | s@oph.ie     |

Postar

| Author_Nickname | Post_Title | Post_Body |
+-----------------+------------+-----------+
| dave            | Blah       | Bla bla   |
| dave            | Stuff      | I like    |
| sophie          | Lorem      | Ipsum     |

Aqui Author_Nickname seria uma chave primária para a tabela de autores e uma chave estrangeira na tabela de postagem. Mesmo que Author_Nickname apareça em duas tabelas, ele ainda corresponde a uma única unidade de informação, ou seja. o nome de cada coluna corresponde a um único campo .

Em muitos casos, não pode haver uma restrição exclusiva nos campos originais; portanto, um campo artificial numérico é usado como chave primária. Isso não altera o fato de que o nome de cada coluna ainda representa um único campo. No design tradicional do banco de dados, os nomes de colunas individuais correspondem a campos únicos, mesmo que não sejam chaves. (por exemplo, usaria part.partname e client.clientname em vez de part.name e client.name ). Esta é a razão para a existência do INNER JOIN ... USING <key>e as NATURAL JOINsintaxes.

No entanto, hoje em dia, e com as camadas ORM prontamente disponíveis em muitos idiomas, os bancos de dados geralmente são projetados como uma camada de persistência para idiomas OO, na qual é natural que variáveis ​​que tenham o mesmo papel em classes diferentes sejam chamadas de iguais ( part.name e client.name , não part.partname e client.clientname ). Nesse contexto, costumo usar 'ID' para minhas chaves primárias.

stilgar
fonte
7

Um fornecedor terceirizado que contratamos para criar algo para nós realmente nomeou todas as suas colunas de identidade Ident apenas para evitar o uso de Id.

Usar "Ident" em vez de "Id" não resolve nada se o "Ident" acabar sendo usado em todas as suas tabelas.

Há um bom artigo sobre convenções de codificação SQL no site Drupal que indica uma boa prática para esta situação:

É uma boa prática prefixar nomes de tabelas com o nome do módulo para evitar possíveis conflitos de namespace.

Desse ponto de vista, CustomerProductId e AgencyGroupAssignmentId fazem sentido usar. Sim, é bem detalhado. Você pode reduzi-lo, mas o ponto mais importante para se preocupar com isso é se o desenvolvedor que o segue ou não entenderá o que você quis dizer . Os IDs precedidos por nomes de tabela detalhados não devem deixar ambiguidade quanto ao que são. E (para mim) isso é mais importante do que salvar algumas teclas.

Aaron
fonte
7

Nomeio minhas colunas como CustomerID em vez de ID, portanto, sempre que digito

FROM dbo.Customers AS c JOIN dbo.CustomerOrders AS o

O prompt SQL sugere imediatamente o seguinte

ON c.CustomerID = o.CustomerID 

Isso me poupa algumas teclas. No entanto, acho que as convenções de nomenclatura são muito subjetivas e, como tal, não tenho uma opinião forte de uma maneira ou de outra.

AK
fonte
5

É a mesma razão pela qual você não nomeará todos os seus campos varchar como "UserText" e "UserText1" ou por que você não usaria "UserDate" e "UserDate1".

Normalmente, se você tem um campo de identidade em uma tabela, é sua chave primária. Como você criaria uma tabela filho com uma chave estrangeira em uma tabela pai se a chave primária nas duas tabelas fosse id?

Nem todo mundo concorda com esse método, mas em meus bancos de dados atribuo uma abreviação exclusiva a cada tabela. O PK para essa tabela seria nomeado PK_ [abbrv] ID. Se isso for usado como um FK em qualquer lugar, eu usaria o FK_ [abbrv] ID. Agora, eu tenho zero trabalho de adivinhação para descobrir quais são os relacionamentos da tabela.

DForck42
fonte
5

Basicamente, pelo mesmo motivo, você normalmente não nomeia os parâmetros parâmetro1, parâmetro2 ... é preciso, mas não descritivo. Se você vir o TableId, provavelmente poderá assumir com segurança que ele é usado para armazenar um pacote para a tabela, independentemente do contexto.

Quanto a quem usou o Ident, ele perdeu completamente o objetivo, dada a escolha entre Ident e Id usar o Id. Ident é ainda mais confuso que Id.

Fora do contexto, pode-se considerar que o ID é a chave principal de alguma tabela (não extremamente útil, a menos que o ID seja um guia), mas o Ident nem diz a você (ou pelo menos a mim) isso. Eu acabaria descobrindo que Ident é a abreviação de identidade (de uma maneira ou de outra), mas o tempo que gastei para descobrir isso seria desperdiçado.

jmoreno
fonte
3

Use um prefixo para que o mesmo nome possa ser usado nos contextos de chave primária e chave estrangeira, para que você possa executar natural join/ join ... using.

DrPizza
fonte