Почему люди рекомендуют не использовать имя «Id» для столбца идентификации?


68

Меня учили не использовать имя Idдля столбца идентификаторов в моих таблицах, но в последнее время я все равно использовал его, потому что оно простое, краткое и очень наглядное описание того, что на самом деле представляют собой данные.

Я видел, как люди предлагают добавлять префикс Idк имени таблицы, но это, кажется, делает больше работы для человека, пишущего запросы SQL (или программиста, если вы используете ORM, такой как Entity Framework), особенно для более длинных имен таблиц, таких как CustomerProductIdили жеAgencyGroupAssignementId

Один сторонний поставщик, которого мы наняли, чтобы создать что-то для нас, на самом деле назвал все их столбцы идентификаторов, Identчтобы не использовать их Id. Сначала я думал, что они сделали это, потому что это Idбыло ключевое слово, но когда я посмотрел на него, я обнаружил, что Idэто не ключевое слово в SQL Server 2005, которое мы используем.

Так почему же люди рекомендуют не использовать имя Idдля столбца идентификаторов?

Изменить: Чтобы уточнить, я не спрашиваю, какое соглашение об именах использовать, или аргументы для использования одного соглашения об именах над другим. Я просто хочу знать, почему не рекомендуется использовать Idимя столбца идентификаторов.

Я один программист, а не dba, и для меня база данных - это просто место для хранения моих данных. Поскольку я обычно создаю небольшие приложения и обычно использую ORM для доступа к данным, с общим именем поля для идентификатора работать намного проще. Делая это, я хочу знать, чего мне не хватает, и есть ли у меня действительно веские причины не делать этого.


10
BF bunfight уже здесь: programmers.stackexchange.com/q/114728/5905 Несколько из нас (читай: я) были втянуты в это ...
gbn

Действительно ли существует такое правило против использования «id» в качестве имени столбца идентификаторов? ActiveRecord, стандартный ORM для Ruby on Rails, делает именно это по соглашению. ar.rubyonrails.org
200_success

1
@ 200_success На уровне базы данных, да. Это сайт базы данных, а не сайт ORM;)
JNK

2
Кроме того, для SQL Server, в частности, см. Dba.stackexchange.com/questions/124655/… и, более конкретно, connect.microsoft.com/SQLServer/feedback/details/2178150
Аарон Бертран

Ответы:


46

Префикс имени таблицы имеет очень веские причины.

Рассмотреть возможность:

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

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

Мы хотим, чтобы DELETEиз TableAзаписей, которые существуют в обеих таблицах. Достаточно просто, мы просто сделаем INNER JOIN:

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

.... и мы просто уничтожили все TableA. Мы случайно сравнили идентификатор B с самим собой - каждая запись соответствовала, и каждая запись была удалена.

Если бы поля были названы, TableAIdи TableBIdэто было бы невозможно ( Invalid field name TableAid in TableB).

Лично у меня нет проблем с использованием имени idв таблице, но на самом деле лучше вводить его перед именем таблицы (или именем сущности, если бы TableAлюди тогда PeopleIdтоже работали бы нормально), чтобы избежать случайного сравнения с неправильным полем и выдувания что-то

Это также делает очень очевидным, откуда берутся поля в длинных запросах с большим количеством JOINs.


10
Таким образом, это в основном соглашение об именах для защиты от ошибок? Я думаю, что использовать begin transactionи commit transactionбыло бы лучше практиковать, чем использовать (imo) более отвратительную схему именования
Рэйчел

13
@Rachel: это для 1. ясности 2. избегать ненужных псевдонимов столбцов 3. разрешить JOIN..USING 4. раздражать обезьян PHP, которые работают в отдельных объектах, а не в наборах
gbn

4
@Rachel Если вы не заметили ошибку при написании запроса и перед тем, как выполнить его, маловероятно, что вы заметите его до совершения. Это случается, зачем делать это более вероятно?
Энди

7
@ И я всегда делаю, SELECTчтобы найти свои записи перед тем, как запускать DELETE, и как только я запускаю инструкцию, я всегда проверяю, что число строк соответствует ожидаемому перед фиксацией.
Рэйчел

5
@Рэйчел Хорошо, что у тебя есть то, что работает для тебя. Можете ли вы заставить всех сделать это?
Энди

36

Главным образом это для того, чтобы иностранные ключи не становились ужасной болью. Допустим, у вас есть две таблицы: Customer и CustomerAddress. Первичным ключом для обоих является столбец с именем id, который является столбцом identity (int).

Теперь вам нужно иметь идентификатор клиента, на который ссылается CustomerAddress. Вы не можете назвать идентификатор столбца, очевидно, поэтому вы идете с customer_id.

Это приводит к паре вопросов. Во-первых, вы должны постоянно помнить, когда вызывать столбец «id», а когда называть его «customer_id». И если вы все испортите, это приведет ко второй проблеме. Если у вас большой запрос с дюжиной или около того объединений, и он не возвращает никаких данных, получайте удовольствие, играя в «Где Уолдо» и выслеживая эту опечатку:

ON c.id = ca.id

Упс, должно было быть ON c.id = ca.customer_id. Или еще лучше, назовите ваши столбцы идентификаторов описательно, чтобы это могло быть ON c.customer_id = ca.customer_id. Тогда, если вы случайно используете неправильный псевдоним таблицы, то customer_id не будет столбцом в этой таблице, и вы получите приятную ошибку компиляции, а не пустые результаты и последующее косоглазие кода.

Конечно, бывают случаи, когда это не помогает, например, если вам нужно несколько взаимосвязей внешнего ключа от одной таблицы к другой отдельной таблице, но присвоение имени всем первичным ключам "id" там тоже не поможет.


27

Вот краткое изложение всех ответов о преимуществах, полученных в результате соглашения об отсутствии общего имени для всех первичных ключей:

  • Меньше ошибок, поскольку поля идентичности не называются одинаковыми

    Вы не можете ошибочно написать запрос, который присоединяется B.Id = B.Idвместо A.Id = B.Id, потому что поля идентичности никогда не будут названы одинаково.

  • Более понятные имена столбцов.

    Если вы посмотрите на названный столбец CustomerId, вы сразу узнаете, какие данные находятся в этом столбце. Если имя столбца было чем-то общим Id, то вам также нужно знать имя таблицы, чтобы знать, какие данные содержит столбец.

  • Избегает ненужных псевдонимов столбцов

    Теперь вы можете написать SELECT CustomerId, ProductIdиз запроса , который соединяется Customersс Products, вместоSELECT Customer.Id as CustomerId, Products.Id as ProductId

  • Позволяет JOIN..USINGсинтаксис

    Вы можете объединять таблицы с синтаксисом Customer JOIN Products USING (CustomerId)вместоCustomer JOIN Products ON Customer.Id = Products.Id

  • Ключ легче найти в поиске

    Если вы ищете поле идентификации клиента в большом решении, поиск CustomerIdбудет гораздо полезнее, чем поискId

Если вы можете подумать о каких-либо других преимуществах соглашения об именах, дайте мне знать, и я добавлю его в список.

Независимо от того, что вы выберете, будьте последовательны :) Независимо от того, решите ли вы использовать уникальные или идентичные имена столбцов для полей идентификаторов.


12

Чтобы скопировать мой ответ из связанного вопроса:

Существует ситуация, когда наклейка «ID» на каждой таблице - не лучшая идея: USINGключевое слово, если оно поддерживается. Мы часто используем его в MySQL.

Например, если у вас есть fooTableстолбец fooTableIdи barTableвнешний ключ fooTableId, ваши запросы могут быть построены так:

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

Это не только экономит набор текста, но и намного более читабельно по сравнению с альтернативой:

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

9

После нормализации схемы базы данных для ограничения избыточности таблицы делятся на меньшие таблицы с установленными отношениями (один к одному, один ко многим, много ко многим). При этом отдельные поля в исходной таблице могут появляться в нескольких нормализованных таблицах.

Например, база данных для блога может выглядеть так в ее ненормализованной форме, предполагая уникальное ограничение на имя_пользователя.

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

Нормализация этого приведет к двум таблицам:

Автор:

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

Почта

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

Здесь Author_Nickname будет первичным ключом для таблицы автора и внешним ключом в таблице записей. Даже если Author_Nickname присутствует в двух таблицах, он все равно соответствует одной единице информации, т.е. Имя каждого столбца соответствует одному полю .

Во многих случаях не может быть уникального ограничения на исходные поля, поэтому вместо первичного ключа используется числовое искусственное поле. Это не меняет того факта, что имя каждого столбца по-прежнему представляет одно поле. В традиционном проектировании базы данных имена отдельных столбцов соответствуют отдельным полям, даже если они не являются ключами. (например, можно использовать part.partname и client.clientname вместо part.name и client.name ). Это причина существования из INNER JOIN ... USING <key>и NATURAL JOINсинтаксисов.

Тем не менее, в настоящее время и с уровнями ORM, легко доступными на многих языках, базы данных часто разрабатываются в качестве уровня персистентности для языков ОО, в которых естественно, что переменные, которые играют одинаковую роль в разных классах, называются одинаковыми ( part.name и client.name , а не part.partname и client.clientname ). В таком контексте я склонен использовать «ID» для моих первичных ключей.


7

Один сторонний поставщик, которого мы наняли, чтобы создать что-то для нас, на самом деле назвал все их столбцы идентификаторов Ident, чтобы избежать использования Id.

Использование «Ident» вместо «Id» на самом деле ничего не решает, если «Ident» в конечном итоге используется на всех их таблицах.

На сайте Drupal есть хорошая статья об соглашениях по SQL-кодированию, которая указывает на хорошую практику для этой ситуации:

Рекомендуется ставить имена таблиц перед именем модуля, чтобы предотвратить возможные конфликты пространства имен.

С этой точки зрения, CustomerProductId и AgencyGroupAssignmentId имеют смысл использовать. Да, это довольно многословно. Вы можете сократить его, но самое главное, о чем следует подумать, поймет ли разработчик, который следует за вами, то, что вы имели в виду . Идентификаторы, начинающиеся с подробных имен таблиц, не должны оставлять двусмысленности относительно того, что они собой представляют. И (для меня) это важнее, чем сохранение нескольких нажатий клавиш.


7

Я называю свои столбцы CustomerID вместо ID, поэтому всякий раз, когда я печатаю

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

SQL Prompt сразу предлагает следующее

ON c.CustomerID = o.CustomerID 

Это спасает меня от нескольких нажатий клавиш. Тем не менее, я думаю, что соглашения об именах очень субъективны, и поэтому у меня нет сильного мнения, так или иначе.


5

Это та же самая причина, по которой вы не назвали бы все свои поля varchar как «UserText» и «UserText1», или почему вы не используете «UserDate» и «UserDate1».

Как правило, если у вас есть поле идентификации в таблице, это ваш первичный ключ. Как бы вы построили дочернюю таблицу с внешним ключом для родительской таблицы, если бы первичным ключом в обеих таблицах был id?

Не все согласны с этим методом, но в своих базах данных я присваиваю уникальные сокращения каждой таблице. PK для этой таблицы будет называться PK_ [abbrv] ID. ЕСЛИ это где-то используется как FK, то я бы использовал FK_ [abbrv] ID. Теперь у меня есть нулевая догадка, чтобы выяснить, каковы отношения таблицы.


5

В основном по той же причине, по которой вы обычно не называете параметры параметр1, параметр2 ... он точный, но не описательный. Если вы видите TableId, то вы можете смело предположить, что он используется для хранения pk для Table, независимо от контекста.

Что касается того, кто использовал Ident, он полностью упускает суть, учитывая выбор между Ident и Id use Id. Идентификатор еще более запутан, чем Ид.

Вне контекста можно предположить, что Id является первичным ключом для некоторой таблицы (не очень полезно, если идентификатор не является guid), но Ident даже не говорит вам (или, по крайней мере, мне) об этом. В конце концов я бы понял, что Иденту не хватает идентичности (так или иначе), но время, потраченное на выяснение этого, будет потрачено впустую.


3

Используйте префикс, чтобы одно и то же имя можно было использовать как в контексте первичного ключа, так и в контексте внешнего ключа, чтобы вы могли выполнить natural join/ join ... using.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.