Зачем использовать автоинкрементный первичный ключ, когда существуют другие уникальные поля? - PullRequest
47 голосов
/ 05 ноября 2010

Я прохожу курс под названием «Системы баз данных», и для нашего учебного проекта я должен разработать веб-сайт.

Вот пример таблицы, которую я создал:

CREATE TABLE users
(
  uid INT NOT NULL AUTO_INCREMENT,
  username VARCHAR(60),
  passhash VARCHAR(255),
  email VARCHAR(60),
  rdate DATE,
  PRIMARY KEY(uid)
);

Профессор сказал мне, что "uid" (идентификатор пользователя) совершенно бесполезен и ненужен, и я должен был использовать имя пользователя в качестве первичного ключа, поскольку никакие два пользователя не могут иметь одинаковое имя пользователя.

Я сказал ему, что мне удобно использовать идентификатор пользователя, потому что, когда я вызываю что-то вроде domain.com/viewuser?id=5, я просто проверяю параметр с помощью: is_numeric($_GET['id']) ... само собой разумеется, он не был убежден .

Поскольку я видел user_id и другие подобные атрибуты (thread_id, comment_id и др.) Во множестве учебных пособий и рассмотрении схемы базы данных популярного программного обеспечения (например, vbulletin), должно быть множество других (более веских) причин.

Итак, мой вопрос: как бы вы обосновали необходимость ненулевого автоматического увеличения идентификатора в качестве первичного ключа по сравнению с использованием другого атрибута, такого как имя пользователя?

Ответы [ 12 ]

81 голосов
/ 05 ноября 2010

Автоинкрементные первичные ключи полезны по нескольким причинам:

  • Они допускают дублирование имен пользователей, как при переполнении стека
  • Они допускают имя пользователя (или адрес электронной почты, если этоиспользуется для входа в систему) быть измененным (легко)
  • Выбирает, объединяет и вставляет быстрее, чем первичные ключи varchar, так как намного быстрее поддерживать числовой индекс
  • Как вы упомянули, проверка становится очень простой: if ((int)$id > 0) { ... }
  • Очистка ввода тривиальна: $id = (int)$_GET['id']
  • Затраты намного меньше, поскольку внешним ключам не нужно дублировать потенциально большие строковые значения

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

Системы с уникальными именами пользователей подходят дляочень небольшое количество пользователей, но Интернет сделал их принципиально сломанными.Если учесть огромное количество людей по имени «Джон», которым, возможно, придется взаимодействовать с веб-сайтом, смешно требовать от каждого из них использовать уникальное отображаемое имя.Это приводит к ужасной системе, которую мы так часто видим со случайными цифрами и буквами, украшающими имя пользователя.

Однако, даже в системе, где вы вводите уникальные имена пользователей, выбор первичного ключа все равно остается плохим.Представьте себе пользователя с 500 сообщениями: внешний ключ в таблице posts будет содержать имя пользователя, дублированное 500 раз.Накладные расходы чрезмерно высоки даже до того, как вы решите, что кому-то может понадобиться изменить свое имя пользователя.

15 голосов
/ 05 ноября 2010

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

10 голосов
/ 05 ноября 2010

Если вы продемонстрировали своему профессору, что присвоение уникального произвольного целого числа каждому пользователю имеет значение для вашего приложения, то, конечно, он будет ошибочно утверждать, что оно «совершенно бесполезно и ненужно».

Однако, возможно, вы упустили его точку зрения.Если он сказал вам, что требование состоит в том, что «никакие два пользователя не могут иметь одно и то же имя пользователя», то вы не выполнили это требование.

Искреннее спасибо за публикацию вашего SQL DDL, это очень полезно, но большинство нене беспокойтесь о SO.

Используя вашу таблицу, я могу сделать следующее:

INSERT INTO users (username) VALUES (NULL);
INSERT INTO users (username) VALUES (NULL);
INSERT INTO users (username) VALUES (NULL);
INSERT INTO users (username) VALUES (NULL);
INSERT INTO users (username) VALUES (NULL);

Что приводит к следующему:

SELECT uid, username, passhash, email, rdate 
FROM users;

uid   username   passhash   email   rdate
1     <NULL>     <NULL>     <NULL>  <NULL>
2     <NULL>     <NULL>     <NULL>  <NULL>
3     <NULL>     <NULL>     <NULL>  <NULL>
4     <NULL>     <NULL>     <NULL>  <NULL>

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

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

7 голосов
/ 05 ноября 2010

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

4 голосов
/ 05 ноября 2010

Ваш профессор поступает правильно, указав, что вы должны были сделать имя пользователя уникальным и не обнуляемым, если требовалось, чтобы имена пользователей были уникальными.UID также может быть ключевым, но если вы не используете его где-то, тогда он не нужен.Более важный аспект дизайна должен заключаться в реализации естественного ключа.Поэтому я согласен с комментарием вашего профессора.

4 голосов
/ 05 ноября 2010

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

1 голос
/ 05 ноября 2010

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

Кроме того, вы можете позже решить, что вам нужны имена пользователейизменить, или что требования к именам пользователей могут измениться (возможно, более длинная строка?).Использование идентификатора предотвращает необходимость изменения всех внешних ключей.

Давайте посмотрим правде в глаза, большинство проектов не собираются расширять это , но вы действительно хотите рискнуть головной болью на 12 месяцев вниздорога, когда вы могли бы сейчас соответствовать хорошим стандартам программирования?

0 голосов
/ 05 ноября 2010

И хотите ли вы сохранить свои имена пользователей в виде открытого текста для кражи?Я бы никогда не подумал об использовании естественного ключа, который мог бы когда-нибудь зашифровать (или зашифровать сейчас).

0 голосов
/ 05 ноября 2010

Поскольку идентификатор пользователя должен быть уникальным (не может быть дублирован) и иногда является индексом.

0 голосов
/ 05 ноября 2010

Я иду со всеми ответами выше. Я бы сказал, что ID легко реализовать, и когда дело доходит до индексации, Int всегда предпочтительнее, чем varchar. Ваш профессор должен знать лучше, почему он должен сказать "нет", что Int id выше меня!

...