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

Зачем использовать автоинкрементный первичный ключ, когда существуют другие уникальные поля?

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

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

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), должно быть много других (более сильных) причин.

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

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

Ответ 3

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

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

Искренняя благодарность за отправку вашего 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 у вас действительно нет никакой целостности данных.

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

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

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

Ответ 8

Например, целочисленный поиск (? id = 5) намного быстрее и имеет более высокую мощность, чем строковый поиск (? username = bob). Другой пример: uid - auto_increment, поэтому вам не нужно вставлять его явно, но он будет автоматически увеличиваться в каждом запросе на вставку.

PS: Ваш проф не так ошибается: D

Ответ 9

мы используем ID для предотвращения дублирования данных, и это может сделать некоторые проакции не сложными (если мы хотим обновить или удалить данные), это более просто, если мы используем ID.

Если вы не хотите использовать ID, вы можете использовать другие поля. но не забудьте сделать их УНИКАЛЬНЫМИ. он может сделать ваши данные превентивными из данных дублирования.

другой путь вне ОСНОВАНИЯ UNIQUE.

Ответ 10

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

Ответ 11

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

Ответ 12

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