Dlaczego ludzie nie zalecają używania nazwy „Id” dla kolumny tożsamości?

68

Nauczono mnie, aby nie używać nazwy Idkolumny tożsamości w moich tabelach, ale ostatnio i tak używam jej, ponieważ jest ona prosta, krótka i bardzo opisowa na temat tego, czym właściwie są dane.

Widziałem, jak ludzie sugerują prefiks Idnazwy tabeli, ale wydaje się, że to po prostu więcej pracy dla osoby piszącej zapytania SQL (lub programisty, jeśli używasz ORM jak Entity Framework), szczególnie w przypadku dłuższych nazw tabel, takich jak CustomerProductIdlubAgencyGroupAssignementId

Jeden zewnętrzny dostawca, którego wynajęliśmy, aby stworzyć dla nas coś, faktycznie nazwał wszystkie swoje kolumny tożsamości, Identaby ich nie używać Id. Na początku myślałem, że to zrobili, ponieważ Idbyło słowem kluczowym, ale kiedy się temu przyjrzałem, zauważyłem, że Idnie jest to słowo kluczowe w SQL Server 2005, którego używamy.

Dlaczego więc ludzie nie zalecają używania nazwy Iddla kolumny tożsamości?

Edycja: Aby wyjaśnić, nie pytam, której konwencji nazewnictwa należy użyć, ani argumentów, aby użyć jednej konwencji nazewnictwa nad drugą. Chcę tylko wiedzieć, dlaczego nie zaleca się używania Idnazwy kolumny tożsamości.

Jestem pojedynczym programistą, nie dba, a dla mnie baza danych jest tylko miejscem do przechowywania moich danych. Ponieważ zwykle buduję małe aplikacje i zwykle używam ORM do dostępu do danych, wspólna nazwa pola dla pola tożsamości jest znacznie łatwiejsza do pracy. Chcę wiedzieć, czego mi brakuje, i czy istnieją naprawdę dobre powody, abym tego nie robił.

Rachel
źródło
10
Bunfight BF już tutaj: programmers.stackexchange.com/q/114728/5905 Kilku z nas (czytaj: ja) zostało do tego wciągniętych ...
gbn
Czy naprawdę istnieje taka reguła, aby nie używać „id” jako nazwy kolumny tożsamości? ActiveRecord, standardowy ORM dla Ruby on Rails, robi to dokładnie zgodnie z konwencją. ar.rubyonrails.org
200_success
1
@ 200_success Na poziomie bazy danych tak. To strona bazy danych, a nie strona ORM;)
JNK
2
Ponadto, w szczególności dla SQL Server, zobacz dba.stackexchange.com/questions/124655/… , a dokładniej connect.microsoft.com/SQLServer/feedback/details/2178150
Aaron Bertrand

Odpowiedzi:

46

Prefiks nazwy tabeli ma bardzo dobre powody.

Rozważać:

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

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

Chcemy DELETEz TableArekordów, które istnieją w obu tabelach. Łatwo zrobimy INNER JOIN:

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

.... i właśnie wymazaliśmy wszystko TableA. Nieumyślnie porównaliśmy identyfikator B z samym sobą - każdy rekord pasował i każdy rekord został usunięty.

Jeśli pola zostały nazwane TableAIdi TableBIdbędzie to niemożliwe ( Invalid field name TableAid in TableB).

Osobiście nie mam problemu z używaniem nazwy idw tabeli, ale naprawdę lepszą praktyką jest przedmowa z nazwą tabeli (lub nazwą encji, jeśli TableAludzie PeopleIdbyliby również w porządku), aby uniknąć przypadkowego porównania z niewłaściwym polem i nadmuchu coś w górze.

To również sprawia, że ​​jest bardzo oczywiste, skąd pochodzą pola w długich zapytaniach z dużą liczbą JOINs.

JNK
źródło
10
Czy to w zasadzie konwencja nazewnictwa w celu ochrony przed błędami? Myślę, że używanie begin transactioni commit transactionbyłoby lepszą praktyką niż używanie (imo) bardziej nieznośnego schematu nazewnictwa
Rachel
13
@Rachel: to dla 1. jasności 2. unikaj niepotrzebnych aliasów kolumn 3. zezwól na DOŁĄCZANIE… USING 4. denerwuj małpy PHP, które pracują w pojedynczych obiektach, a nie w zestawach
gbn
4
@Rachel Jeśli nie zauważyłeś błędu podczas pisania zapytania i tuż przed jego wykonaniem, jest mało prawdopodobne, że zauważysz go przed popełnieniem. Te rzeczy się zdarzają, dlaczego zwiększają to prawdopodobieństwo?
Andy
7
@Andy zawsze staram SELECTsię znaleźć moje rekordy przed uruchomieniem DELETE, a po uruchomieniu instrukcji zawsze sprawdzam, czy liczba wierszy jest zgodna z oczekiwaniami przed zatwierdzeniem.
Rachel
5
@Rachel To miło, że masz coś, co działa dla Ciebie. Czy możesz zmusić wszystkich do tego?
Andy,
36

Głównie ma to na celu powstrzymanie obcych kluczy przed ogromnym bólem. Załóżmy, że masz dwie tabele: Customer i CustomerAddress. Kluczem podstawowym dla obu jest kolumna o nazwie id, która jest kolumną tożsamości (int).

Teraz musisz podać identyfikator klienta z CustomerAddress. Oczywiście nie możesz nazwać identyfikatora kolumny, więc idziesz do id_klienta.

Prowadzi to do kilku problemów. Po pierwsze, musisz konsekwentnie pamiętać, kiedy wywołać kolumnę „id”, a kiedy nazwać „ID_użytkownika”. A jeśli to zepsujesz, prowadzi to do drugiego problemu. Jeśli masz duże zapytanie z kilkunastoma złączeniami i nie zwraca ono żadnych danych, baw się dobrze grając w Where's Waldo i wyszukując tę ​​literówkę:

ON c.id = ca.id

Ups, powinno być ON c.id = ca.customer_id. Lub jeszcze lepiej, nazwij kolumny tożsamości opisowo, aby tak było ON c.customer_id = ca.customer_id. Jeśli przypadkowo użyjesz gdzieś niewłaściwego aliasu tabeli, identyfikator_użytkownika nie będzie kolumną w tej tabeli, a otrzymasz ładny błąd kompilacji, zamiast pustych wyników i późniejszego zezowania kodu.

To prawda, że ​​są przypadki, w których to nie pomaga, na przykład jeśli potrzebujesz wielu relacji kluczy obcych z jednej tabeli do innej pojedynczej tabeli, ale nazywanie wszystkich kluczy podstawowych „id” też tam nie pomaga.

db2
źródło
27

Oto podsumowanie wszystkich odpowiedzi na temat korzyści uzyskanych dzięki konwencji, że nie można używać wspólnej nazwy dla wszystkich kluczy podstawowych:

  • Mniej błędów, ponieważ pola tożsamości nie są nazywane tak samo

    Nie można przez pomyłkę napisać zapytania, które łączy się B.Id = B.Idzamiast A.Id = B.Id, ponieważ pola tożsamości nigdy nie będą miały takich samych nazw.

  • Jaśniejsze nazwy kolumn.

    Jeśli spojrzysz na kolumnę o nazwie CustomerId, natychmiast wiesz, jakie dane są w tej kolumnie. Jeśli nazwa kolumny była czymś ogólnym Id, musisz znać nazwę tabeli, aby wiedzieć, jakie dane zawiera kolumna.

  • Unika niepotrzebnych aliasów kolumn

    Możesz teraz pisać SELECT CustomerId, ProductIdz zapytania, które łączy Customerssię Products, zamiastSELECT Customer.Id as CustomerId, Products.Id as ProductId

  • Umożliwia JOIN..USINGskładni

    Możesz łączyć tabele ze składnią Customer JOIN Products USING (CustomerId)zamiastCustomer JOIN Products ON Customer.Id = Products.Id

  • Klucz jest łatwiejszy do znalezienia podczas wyszukiwania

    Jeśli szukasz pola tożsamości klienta w dużym rozwiązaniu, wyszukiwanie CustomerIdjest o wiele bardziej przydatne niż wyszukiwanieId

Jeśli możesz pomyśleć o innych zaletach tej konwencji nazewnictwa, daj mi znać, a dodam ją do listy.

To, czy zdecydujesz się użyć unikatowych lub identycznych nazw kolumn dla pól tożsamości, zależy od ciebie, ale niezależnie od tego, co wybierzesz, zachowaj spójność :)

Rachel
źródło
12

Aby skopiować moją odpowiedź z połączonego pytania:

Jest sytuacja, w której umieszczenie „ID” na każdym stole nie jest najlepszym pomysłem: USINGsłowo kluczowe, jeśli jest obsługiwane. Używamy go często w MySQL.

Na przykład, jeśli masz fooTablekolumnę fooTableIdi barTableklucz obcy fooTableId, twoje zapytania mogą być skonstruowane jako takie:

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

Nie tylko oszczędza pisania, ale jest znacznie bardziej czytelny w porównaniu do alternatywy:

SELECT fooTable.Id, fooField1, barField2 FROM fooTable INNER JOIN barTable ON (fooTable.Id = barTable.foTableId)
Izkata
źródło
9

Po znormalizowaniu schematu bazy danych w celu ograniczenia redundancji tabele są dzielone na mniejsze tabele o ustalonych relacjach (jeden do jednego, jeden do wielu, wiele do wielu). W tym procesie pojedyncze pola w oryginalnej tabeli mogą pojawiać się w wielu znormalizowanych tabelach.

Na przykład baza danych bloga mogłaby wyglądać tak w nienormalizowanej formie, zakładając unikalne ograniczenie dla nazwy Autor_Nick.

| 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     |

Normalizacja go dałaby dwie tabele:

Autor:

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

Poczta

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

W tym przypadku nazwa_nazwa_autora byłaby kluczem podstawowym do tabeli autorów i kluczem obcym w tabeli wpisów. Nawet jeśli nazwa Autor_nazwa pojawia się w dwóch tabelach, nadal odpowiada jednej jednostce informacji, tj. nazwa każdej kolumny odpowiada jednemu polu .

W wielu przypadkach nie może istnieć unikalne ograniczenie oryginalnych pól, dlatego zamiast klucza podstawowego stosuje się sztuczne pole numeryczne. Nie zmienia to faktu, że nazwa każdej kolumny wciąż reprezentuje jedno pole. W tradycyjnym projekcie bazy danych nazwy poszczególnych kolumn odpowiadają pojedynczym polom, nawet jeśli nie są kluczami. (np. należy użyć part.partname i client.clientname zamiast part.name i client.name ). To jest powód istnienia INNER JOIN ... USING <key>i NATURAL JOINskładni.

Jednak obecnie, a warstwy ORM są łatwo dostępne w wielu językach, bazy danych są często zaprojektowane jako warstwa utrwalająca dla języków OO, w których naturalne jest, że zmienne, które pełnią tę samą rolę w różnych klasach, nazywane są takimi samymi ( part.name i client.name nie part.partname i client.clientname ). W takim kontekście używam „ID” dla moich kluczy podstawowych.

stilgar
źródło
7

Jeden zewnętrzny dostawca, którego wynajęliśmy, aby stworzyć dla nas coś, faktycznie nazwał wszystkie swoje kolumny tożsamości Ident, aby uniknąć używania Id.

Użycie „Ident” zamiast „Id” tak naprawdę niczego nie rozwiązuje, jeśli „Ident” ostatecznie zostanie użyte na wszystkich stołach.

Na stronie Drupal znajduje się dobry artykuł na temat konwencji kodowania SQL, który wskazuje dobrą praktykę w tej sytuacji:

Dobrą praktyką jest poprzedzanie nazw tabel nazwą modułu, aby zapobiec możliwym konfliktom przestrzeni nazw.

Z tego punktu widzenia sensowne jest użycie CustomerProductId i AgencyGroupAssignmentId. Tak, to dość gadatliwe. Możesz go skrócić, ale najważniejszą rzeczą, na którą należy się wtedy zwrócić, jest to, czy programista, który cię śledzi, zrozumie, co miałeś na myśli . Identyfikatory poprzedzone pełnymi nazwami tabel nie powinny pozostawiać dwuznaczności co do tego, czym są. I (dla mnie) jest to ważniejsze niż zapisanie kilku naciśnięć klawiszy.

Aaron
źródło
7

Nazwij moje kolumny CustomerID zamiast ID, więc za każdym razem, gdy piszę

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

Monit SQL natychmiast sugeruje, co następuje

ON c.CustomerID = o.CustomerID 

Oszczędza mi to kilka naciśnięć klawiszy. Uważam jednak, że konwencje nazewnictwa są bardzo subiektywne i jako takie nie mam silnej opinii w ten czy inny sposób.

AK
źródło
5

Jest to ten sam powód, dla którego nie nazwałbyś wszystkich swoich pól varchar coś w rodzaju „UserText” i „UserText1”, lub dlaczego nie używałbyś „UserDate” i „UserDate1”.

Zazwyczaj, jeśli masz pole tożsamości w tabeli, jest to twój klucz podstawowy. Jak zbudowałbyś tabelę podrzędną z kluczem obcym do tabeli nadrzędnej, gdyby kluczem podstawowym w obu tabelach był identyfikator?

Nie wszyscy zgadzają się z tą metodą, ale w moich bazach danych przypisuję unikalny skrót do każdej tabeli. PK dla tej tabeli nosi nazwę PK_ [abbrv] ID. JEŻELI jest używany jako FK gdziekolwiek, wtedy użyłbym identyfikatora FK_ [abbrv]. Teraz nie zastanawiam się nad tym, jakie są relacje między tabelami.

DForck42
źródło
5

Zasadniczo z tego samego powodu, dla którego zwykle nie nazywa się parametrów parametr1, parametr2 ... jest dokładny, ale nie opisowy. Jeśli widzisz TableId, prawdopodobnie możesz bezpiecznie założyć, że jest on używany do przechowywania pk dla Table, niezależnie od kontekstu.

Jeśli chodzi o tego, kto używał Ident, całkowicie nie rozumie sensu, mając wybór między Ident a Id. Ident jest jeszcze bardziej mylący niż Id.

Poza kontekstem można założyć, że Id jest kluczem podstawowym do niektórych tabel (nie jest to szczególnie przydatne, chyba że identyfikator jest przewodnikiem), ale Ident nawet o tym nie mówi (a przynajmniej mnie). W końcu doszłam do wniosku, że Ident jest skrótem od tożsamości (w taki czy inny sposób), ale czas, który spędziłem, zastanawiając się nad tym, byłby zmarnowany.

jmoreno
źródło
3

Użyj prefiksu, aby ta sama nazwa mogła być używana zarówno w kontekście klucza podstawowego, jak i klucza obcego, abyś mógł wykonać natural join/ join ... using.

DrPizza
źródło