Я полагаю, что вашим хранилищем по умолчанию является MyISAM, который игнорирует ограничения внешнего ключа. Он молча принимает объявление внешнего ключа, но не сохраняет ограничение и не применяет его впоследствии.
Однако он неявно создает индекс для столбцов, которые вы объявили для внешнего ключа. В MySQL «KEY
» является синонимом «INDEX
». Вот что показано в выводе DESCRIBE: индекс, но не ограничение.
Вы можете вставить недопустимые значения в таблицу прямо сейчас, потому что нет ограничений. Чтобы получить ограничение, обеспечивающее ссылочную целостность, вы должны использовать механизм хранения InnoDB:
CREATE TABLE actions (
A_id int NOT NULL AUTO_INCREMENT,
...
CONSTRAINT fk_Question FOREIGN KEY (Q_id) REFERENCES questions(P_id),
CONSTRAINT fk_User FOREIGN KEY (U_id) REFERENCES users(P_id)
) ENGINE=InnoDB;
Я всегда думал, что со стороны MySQL было большой ошибкой молча игнорировать объявления ограничений внешнего ключа. Там нет ошибки или предупреждения, что механизм хранения не поддерживает их.
То же самое верно для ограничений CHECK. Кстати, ни один механизм хранения, используемый с MySQL, не поддерживает ограничения CHECK, но синтаксический анализатор SQL принимает их без жалоб.
Ошибка errno 150 возникает, когда она не может создать таблицу InnoDB, поскольку не может понять смысл ограничения внешнего ключа. Вы можете получить больше информации с помощью:
SHOW ENGINE INNODB STATUS;
Некоторые требования для внешних ключей InnoDB:
- Ссылочная таблица также должна быть InnoDB.
- Ссылочная таблица должна иметь индекс и первичный ключ.
- Типы данных SQL для столбца FK и столбца PK со ссылкой должны быть идентичными. Например, INT не соответствует BIGINT или INT UNSIGNED.
Вы можете изменить механизм хранения таблицы, в которой есть данные:
ALTER TABLE actions ENGINE=InnoDB;
Это фактически копирует всю таблицу MyISAM в таблицу InnoDB, а затем, после успешного завершения, удаляет таблицу MyISAM и переименовывает новую таблицу InnoDB в имя прежней таблицы MyISAM. Это называется «реструктуризацией таблицы» и может занимать много времени, в зависимости от того, сколько данных в таблице. Перестройка таблицы происходит во время ALTER TABLE, даже в некоторых случаях, когда это может показаться ненужным.
Re ваше обновление 2:
Мне сказали, что важно обеспечить целостность данных с помощью функциональных внешних ключей, но также и то, что InnoDB не следует использовать с MySQL. Что вы рекомендуете?
Кто тебе это сказал? Это абсолютно неверно. InnoDB имеет лучшую производительность, чем MyISAM (хотя InnoDB требует большего внимания к настройке конфигурации ), InnoDB поддерживает атомарные изменения, транзакции, внешние ключи, а InnoDB гораздо более устойчив к повреждению данных в авария.
Если вы не используете старую неподдерживаемую версию MySQL (5.0 или более раннюю), вы должны использовать InnoDB в качестве используемого по умолчанию механизма хранения и использовать MyISAM, только если вы можете продемонстрировать конкретную рабочую нагрузку, которая дает преимущества от MyISAM.