我猜你的默认存储引擎是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 犯了一个很大的错误silently忽略外键约束声明。没有错误或警告表明存储引擎不支持它们。
MySQL 8.0.16之前的CHECK约束也是如此。 MySQL 使用的存储引擎均不支持 CHECK 约束,但 SQL 解析器毫无怨言地接受它们。在8.0.16及更高版本中,InnoDB表确实支持CHECK约束,但其他存储引擎仍然忽略它们。
当无法创建 InnoDB 表时,会出现 errno 150 问题,因为它无法理解外键约束。您可以通过以下方式获取更多信息:
SHOW ENGINE INNODB STATUS;
InnoDB 外键的一些要求:
- 引用的表也必须是 InnoDB。
- 引用的表必须有索引和主键。
- FK 列和引用的 PK 列的 SQL 数据类型必须相同。例如,INT 与 BIGINT 或 INT UNSIGNED 不匹配。
您可以更改其中包含数据的表的存储引擎:
ALTER TABLE actions ENGINE=InnoDB;
这有效地将整个 MyISAM 表复制到 InnoDB 表,然后一旦成功,它就会删除 MyISAM 表并将新的 InnoDB 表重命名为以前的 MyISAM 表的名称。这称为“表重组”,它可能非常耗时,具体取决于表中的数据量。表重组发生在 ALTER TABLE 期间,即使在某些情况下似乎没有必要。
回复您的更新2:
有人告诉我,使用功能外键强制数据完整性很重要,但 InnoDB 不应该与 MySQL 一起使用。你有什么建议吗?
谁告诉你的?这绝对是假的。InnoDB 比 MyISAM 性能更好 http://www.mysqlperformanceblog.com/2007/01/08/innodb-vs-myisam-vs-falcon-benchmarks-part-1/(虽然InnoDB需要更多关注调整配置 http://www.mysqlperformanceblog.com/2006/09/29/what-to-tune-in-mysql-server-after-installation/),InnoDB 支持原子更改、事务、外键,并且 InnoDB 更能抵抗崩溃中损坏的数据。
除非您运行的是旧的、不受支持的 MySQL 版本(5.0 或更早版本),否则您应该使用 InnoDB 作为您的数据库。default存储引擎选择,并且仅当您可以演示可以从 MyISAM 受益的特定工作负载时才使用 MyISAM。