Разница терминов MySQL "ограничения" и "внешние ключи"?

Я смотрю на docs здесь и пытаясь разобраться в различии между FOREIGN KEYs и CONSTRAINT. Я думал, что ограничение FK было, но документы, похоже, говорят о них, как о разных вещах.

Синтаксис для создания FK (частично)...

[CONSTRAINT [symbol]] FOREIGN KEY
    [index_name] (index_col_name, ...)
    REFERENCES tbl_name (index_col_name,...)

Таким образом, предложение CONSTRAINT необязательно. Почему вы включили его или не включили? Если вы оставите это, MySQL создает внешний ключ, но не ограничение? Или это скорее похоже на "CONSTRAINT" - это не что иное, как имя для вас FK, поэтому, если вы не укажете его, вы получите анонимный FK?

Любое разъяснение будет принята с благодарностью.

Спасибо,

Этан

Ответ 1

Да, внешний ключ является типом ограничений. MySQL имеет неравномерную поддержку ограничений:

  • PRIMARY KEY: да как ограничение таблицы и ограничение столбца.
  • FOREIGN KEY: да как ограничение таблицы, но только с системами хранения InnoDB и BDB; в противном случае анализируется, но игнорируется.
  • CHECK: анализируется, но игнорируется во всех механизмах хранения.
  • UNIQUE: да как ограничение таблицы и ограничение столбца.
  • NOT NULL: да как ограничение столбца.
  • DEFERRABLE и другие атрибуты ограничений: нет поддержки.

Предложение CONSTRAINT позволяет явно указывать ограничение, чтобы сделать метаданные более читабельными или использовать имя, если вы хотите отказаться от ограничения. Стандарт SQL требует, чтобы предложение CONSTRAINT было необязательным. Если вы оставите это, RDBMS создаст имя автоматически, и имя будет соответствовать реализации.

Ответ 2

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

Возвращаясь к конкретному вопросу, вы правы, но часть CONSTRAINT [symbol] создаст FK с автогенерированным именем.

Ответ 3

Невозможно ответить для MySQL, но FK - это ограничения. Все, что заставляет ваши данные в определенном состоянии, является ограничением. Существует несколько видов ограничений, все ограничения - уникальный, первичный ключ, проверка и внешние ключи. Возможно, у MySQL есть другие.

Иногда слова допускаются в командах, но не требуются для чтения, как FROM в инструкции DELETE.

Ответ 4

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

Ответ 5

На данный момент наши CREATE TABLE DDL имеют такой формат - обратите внимание на синтаксис определения UNIQUE KEY и FOREIGN KEY, который мы использовали.

CREATE TABLE my_dbschema.my_table (
    id INT unsigned auto_increment PRIMARY KEY,
    account_nbr INT NOT NULL,
    account_name VARCHAR(50) NOT NULL,
    active_flg CHAR(1) NOT NULL DEFAULT 'Y',
    vendor_nbr INT NOT NULL,
    create_ts TIMESTAMP NOT NULL DEFAULT current_timestamp,
    create_usr_id VARCHAR(10) NOT NULL DEFAULT 'DFLTUSR',
    last_upd_ts TIMESTAMP NOT NULL DEFAULT current_timestamp ON UPDATE current_timestamp,
    last_upd_usr_id VARCHAR(10) NOT NULL DEFAULT 'DFLTUSR',
    UNIQUE KEY uk1_my_table(account_nbr, account_name),
    FOREIGN KEY fk1_my_table(vendor_nbr) REFERENCES vendor(vendor_nbr)
    );

В этом формате MySQL создает INDEX-es с именами uk1_my_table и fk1_my_table автоматически; но имя объекта FK является чем-то другим - my_table_ibfk_1 (т.е. tablename_ibfk_N - система определена). Таким образом, ALTER TABLE my_table DROP FOREIGN KEY fk1_my_table не работает (и, следовательно, расстраивает и поднимает тревогу), поскольку этим объектом не является объект FK db.

Вот альтернативный формат DDL по сравнению с константами (Ref: https://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html): -

CREATE TABLE my_dbschema.my_table (
    id INT unsigned auto_increment PRIMARY KEY,
    account_nbr INT NOT NULL,
    account_name VARCHAR(50) NOT NULL,
    active_flg CHAR(1) NOT NULL DEFAULT 'Y',
    vendor_nbr INT NOT NULL,
    create_ts TIMESTAMP NOT NULL DEFAULT current_timestamp,
    create_usr_id VARCHAR(10) NOT NULL DEFAULT 'DFLTUSR',
    last_upd_ts TIMESTAMP NOT NULL DEFAULT current_timestamp ON UPDATE current_timestamp,
    last_upd_usr_id VARCHAR(10) NOT NULL DEFAULT 'DFLTUSR',
    CONSTRAINT uk1_my_table UNIQUE KEY (account_nbr, account_name),
    CONSTRAINT fk1_my_table FOREIGN KEY (vendor_nbr) REFERENCES vendor(vendor_nbr)
    );

В этом формате MySQL по-прежнему создает INDEX-es с именами uk1_my_table и fk1_my_table автоматически, но имя объекта FK не является чем-то другим - его fk1_my_table, как указано в DDL. Таким образом, ALTER TABLE my_table DROP FOREIGN KEY fk1_my_table работает, но оставляет позади INDEX.

И обратите внимание, что ALTER TABLE my_table DROP INDEX fk1_my_table обычно не работает (когда FK еще не упал), с сообщением об ошибке, которое оно используется в FK! Если команда DROP FK выполнена успешно, то работает только DROP INDEX.

Надеюсь, что это объяснит и поможет устранить путаницу.

Ответ 6

Это, вероятно, самый запутанный topìc в MySQL.

Многие говорят, что, например, "ПЕРВИЧНЫЙ КЛЮЧ", "ИНОСТРАННЫЙ КЛЮЧ" и ключ "УНИКАЛЬНЫЙ" являются фактически индексами! (Официальная документация MySQL включена здесь)

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

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

Пример:

... FOREIGN KEY index_name (col_name1, col_name2,...)

Если FOREIGN KEY является индексом, тогда мы должны иметь возможность использовать index_name для его обработки. Однако мы не можем.

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

В любом случае мы не знаем. Собственно, никто не знает.