Ключи и связи между таблицами в SQL - Вопросы
Всего: 6 вопросов
1. Что такое ключ в базе данных и какие бывают ключи в SQL?
Что такое ключ в базе данных и какие бывают ключи в SQL?
Ключ — столбец или набор столбцов, по которому строку можно однозначно найти или связать со строкой другой таблицы. Ключи работают как ограничения: СУБД сама отклоняет запросы, которые нарушают уникальность или ссылаются на несуществующие строки.
В SQL объявляют три вида ключей:
PRIMARY KEY— первичный: однозначно определяет строку, уникален, неNULL, один на таблицу;UNIQUE— уникальный: запрещает повтор значений;FOREIGN KEY— внешний: связывает строку с другой таблицей.
Остальные названия описывают, как ключ выбран и из чего состоит: потенциальный (candidate) — любой столбец, который мог бы стать первичным ключом; альтернативный (alternate) — потенциальный, не выбранный первичным, объявляется как UNIQUE; естественный — из данных предметной области (email); суррогатный — искусственный id; составной — из нескольких столбцов, уникальна только их комбинация, например PRIMARY KEY (topic_id, tag_id).
2. Чем естественный ключ отличается от суррогатного и какой выбрать для первичного ключа?
Чем естественный ключ отличается от суррогатного и какой выбрать для первичного ключа?
Естественный ключ берётся из данных предметной области, например email. Суррогатный — искусственный столбец без смысла в предметной области, например id INT AUTO_INCREMENT.
- Естественный ключ может измениться: пользователь сменил email — придётся обновлять все ссылки. Суррогатный номер присваивается один раз.
- В связанных таблицах естественный ключ занимает строку до 100 символов в каждой ссылке, суррогатный — 4 байта (
INT) или 8 байт (BIGINT). - Естественный ключ сам гарантирует уникальность данных; при суррогатном на email нужно отдельное ограничение
UNIQUE. - В Hibernate/JPA суррогатный ключ — стандартный вариант: поле с
@Idи@GeneratedValue.
Поэтому в Java-приложениях почти всегда выбирают суррогатный ключ. Номера AUTO_INCREMENT не обязаны идти подряд: неудачная вставка или откат транзакции может «съесть» значение.
3. Чем UNIQUE отличается от PRIMARY KEY и может ли уникальный столбец содержать NULL?
Чем UNIQUE отличается от PRIMARY KEY и может ли уникальный столбец содержать NULL?
Оба ограничения запрещают повторы и автоматически создают индекс, но:
PRIMARY KEYв таблице один,UNIQUE— сколько угодно;PRIMARY KEYне допускаетNULL, а столбец сUNIQUEможет содержатьNULL, если не объявленNOT NULL;- внешний ключ обычно ссылается на
PRIMARY KEY, наUNIQUE— редко.
UNIQUE защищает альтернативные ключи — логин и email пользователя. В MySQL, PostgreSQL и Oracle уникальный столбец может хранить сколько угодно NULL: по стандарту SQL два неизвестных значения не равны. SQL Server допускает только один NULL — частая неожиданность при переносе схемы.
Ограничению можно дать имя: CONSTRAINT uq_users_phone UNIQUE (phone). Оно видно в сообщении об ошибке 1062, и по нему ограничение удаляют.
4. Что такое внешний ключ (FOREIGN KEY) и что MySQL требует для его создания?
Что такое внешний ключ (FOREIGN KEY) и что MySQL требует для его создания?
Внешний ключ — столбец дочерней таблицы, значение которого должно совпадать с первичным (или уникальным) ключом строки родительской таблицы. СУБД не даст создать тему с несуществующим автором (ошибка 1452) и удалить пользователя, у которого есть темы (ошибка 1451).
CONSTRAINT fk_topics_author FOREIGN KEY (author_id)
REFERENCES users (id)
Требования MySQL:
- обе таблицы на движке InnoDB — MyISAM принимает синтаксис, но молча игнорирует ключ;
- типы столбцов совпадают:
INTссылается наINT, а не наBIGINTилиINT UNSIGNED(иначе ошибка 3780); у строк совпадают кодировка и collation; - ссылка идёт на
PRIMARY KEYилиUNIQUEродительской таблицы (с MySQL 8.4 ссылка на неуникальный индекс по умолчанию запрещена); - родительская таблица создаётся раньше дочерней (иначе ошибка 1824).
Индекс по столбцу внешнего ключа MySQL создаёт сам, если подходящего нет. SET FOREIGN_KEY_CHECKS = 0 отключает проверку, и после включения уже вставленные ссылки не перепроверяются.
5. Какие действия можно задать в ON DELETE и ON UPDATE и когда их использовать?
Какие действия можно задать в ON DELETE и ON UPDATE и когда их использовать?
ON DELETE и ON UPDATE задают, что сделать с дочерними строками, когда родительскую строку удаляют или меняют её ключ:
RESTRICT— операция отклоняется с ошибкой 1451; для данных, которые нельзя терять (заказы, платежи);NO ACTION— в InnoDB работает какRESTRICTи действует по умолчанию;CASCADE— дочерние строки удаляются или обновляются вместе с родительской; когда они без родителя не имеют смысла (сообщения темы, теги темы);SET NULL— внешний ключ становитсяNULL, столбец должен допускатьNULL; когда связь необязательна (сообщение остаётся, автор неизвестен);SET DEFAULT— InnoDB такую таблицу не создаст, в MySQL не используется.
CONSTRAINT fk_messages_topic FOREIGN KEY (topic_id)
REFERENCES topics (id) ON DELETE CASCADE,
CONSTRAINT fk_messages_author FOREIGN KEY (author_id)
REFERENCES users (id) ON DELETE SET NULL
CASCADE срабатывает по цепочке на каждом уровне, поэтому его ставят только там, где дочерние строки действительно не нужны. ON UPDATE CASCADE нужен редко: суррогатный id не меняется; он полезен при ссылке на естественный ключ, например на код страны.
6. Какие бывают связи между таблицами и как каждую реализовать в SQL?
Какие бывают связи между таблицами и как каждую реализовать в SQL?
Три вида связей:
- Один к одному (1:1), пользователь — профиль: внешний ключ, который одновременно первичный или
UNIQUE(user_profiles.user_id). БезUNIQUEполучится один ко многим. - Один ко многим (1:M), пользователь — его темы: внешний ключ на стороне «многие» (
topics.author_id), а не вusers. - Многие ко многим (M:N), темы — теги: одним внешним ключом не выразить, нужна промежуточная таблица с двумя внешними ключами и составным первичным ключом.
CREATE TABLE topic_tags (
topic_id INT NOT NULL,
tag_id INT NOT NULL,
PRIMARY KEY (topic_id, tag_id),
CONSTRAINT fk_topic_tags_topic FOREIGN KEY (topic_id)
REFERENCES topics (id) ON DELETE CASCADE,
CONSTRAINT fk_topic_tags_tag FOREIGN KEY (tag_id)
REFERENCES tags (id) ON DELETE CASCADE
);
Составной ключ не даёт пометить тему одним тегом дважды. В JPA такую связь описывает @ManyToMany с @JoinTable.