ChatGPT解决这个技术问题 Extra ChatGPT

如何在 MySQL 中临时禁用外键约束?

是否可以暂时禁用 MySQL 中的约束?

我有两个 Django 模型,每个模型都有一个指向另一个模型的外键。由于外键约束,删除模型实例会返回错误:

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n)
transaction.commit_unless_managed()  #a foreign key constraint fails here

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n)
transaction.commit_unless_managed()

是否可以暂时禁用约束并删除?

要么我没有得到你想要做的事情,要么你想做的事情非常、非常、非常丑陋。即使你能做到,你也不应该这样做。
删除并重新应用 FK 正在更改您的数据库。你试图挑战那些让系统有某种意义的限制,它没有考虑到 FK 可能是一个临时的东西,如果它知道,它会恐慌。
你想做什么很奇怪。但是您使用的是哪个数据库?
如果您没有禁用约束,而是将其永久修改为 ON DELETE SET NULL,该怎么办?这将完成类似的事情,您不必打开和关闭密钥检查。
@dnagirl:确实会更好。我怎样才能做到这一点?

P
Peter Mortensen

尝试 DISABLE KEYS

SET FOREIGN_KEY_CHECKS=0;

确保

SET FOREIGN_KEY_CHECKS=1;

后。


这是为整个 mysql 设置的东西还是只是那个会话?
我相信这是每个会话。
我可以只为单个表禁用 FOREIGN_KEY_CHECKS 吗?
澄清@Pacerier 的评论:对于 Innodb,您不能DISABLE KEYS。但是您可以使用显示的其他命令完成此问题中的要求:SET FOREIGN_KEY_CHECKS=0;(起初我以为他说没有办法完成此操作。)
b
berniey

要全局关闭外键约束,请执行以下操作:

SET GLOBAL FOREIGN_KEY_CHECKS=0;

完成后记得把它放回去

SET GLOBAL FOREIGN_KEY_CHECKS=1;

警告:只有在进行单用户模式维护时才应该这样做。因为它可能导致数据不一致。例如,当您使用 mysqldump 输出上传大量数据时,它将非常有用。


这是我需要知道的,所以这不是很好的做法,但是这个家伙的答案应该得分更高......
在尝试“最佳答案”对我不起作用之后,这对我有用。也许可以添加对差异的解释。
@hexnet 不同之处在于,只有 SET FOREIGN_KEY_CHECKS 只是更改了 当前连接 的值,而 SET GLOBAL .. 更改了 所有连接 的值,包括未来的连接。如果您只是在一个窗口中执行 SET FOREIGN..,然后尝试在不同的窗口(通过不同的连接)应用该语句,则该值没有改变。使用 GLOBAL,相同的变量对于两个连接具有相同的值。
播放更大的转储(6+ GB)<3时唯一可以帮助我的东西
这对我不起作用。当我尝试时,我看到:ERROR 1228 (HY000): Variable 'foreign_key_checks' is a SESSION variable and can't be used with SET GLOBAL
A
AntonioCS

我通常只在我想截断表时禁用外键约束,并且由于我不断回到这个答案,这是为了将来的我:

SET FOREIGN_KEY_CHECKS=0;
TRUNCATE TABLE table;
SET FOREIGN_KEY_CHECKS=1;

d
dnagirl

与其禁用约束,不如将其永久修改为 ON DELETE SET NULL。这将完成类似的事情,您不必打开和关闭密钥检查。像这样:

ALTER TABLE tablename1 DROP FOREIGN KEY fk_name1; //get rid of current constraints
ALTER TABLE tablename2 DROP FOREIGN KEY fk_name2;

ALTER TABLE tablename1 
  ADD FOREIGN KEY (table2_id) 
        REFERENCES table2(id)
        ON DELETE SET NULL  //add back constraint

ALTER TABLE tablename2 
  ADD FOREIGN KEY (table1_id) 
        REFERENCES table1(id)
        ON DELETE SET NULL //add back other constraint

阅读此 (http://dev.mysql.com/doc/refman/5.5/en/alter-table.html) 和此 (http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html)。


注意更改表可能需要很长时间,最好将服务器全局设置为 FOREIGN_KEY_CHECKS 为 0 并在脏工作完成后将其放回原处。此外,它可能会锁定以写入您的表格。
更改远程列类型时不会破坏引用吗? (看来我的客户将修改后的临时表重命名为原始表名。)
P
Peter Mortensen

全局关闭外键约束:

SET GLOBAL FOREIGN_KEY_CHECKS = 0;

对于活动外键约束:

SET GLOBAL FOREIGN_KEY_CHECKS = 1;

P
Peter Mortensen

phpMyAdmin 的一个非常简单的解决方案:

在您的表中,转到 SQL 选项卡

编辑要运行的 SQL 命令后,GO 旁边有一个复选框,名为 'Enable foreign key checks' 。

取消选中此复选框并运行您的 SQL。执行后会自动复查。


谢谢!事实上,解决方案 SET FOREIGN_KEY_CHECKS=0; ..... SET FOREIGN_KEY_CHECKS=1; 在 PHPMyAdmin 中对我不起作用,因为我忘记取消选中“启用外键检查”复选框。在 PHPMyAdmin 中,您可以跳过这些 SET 命令并取消选中该复选框。
R
RotS

对我来说,仅 SET FOREIGN_KEY_CHECKS=0; 是不够的。我还有一个com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException

我必须添加 ALTER TABLE myTable DISABLE KEYS;

所以:

SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE myTable DISABLE KEYS;
DELETE FROM myTable;
ALTER TABLE myTable ENABLE KEYS;
SET FOREIGN_KEY_CHECKS=1;

仅供参考,mySQL 5.7 抛出警告,InnoDB 引擎在运行 DISABLE KEYS 命令时没有此选项。
这确实有效,没有alter table它也对我不起作用
C
Chanoch

如果键字段可以为空,那么您还可以在尝试删除它之前将值设置为空:

cursor.execute("UPDATE myapp_item SET myapp_style_id = NULL WHERE n = %s", n)
transaction.commit_unless_managed() 

cursor.execute("UPDATE myapp_style SET myapp_item_id = NULL WHERE n = %s", n)
transaction.commit_unless_managed()

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n)
transaction.commit_unless_managed()

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n)
transaction.commit_unless_managed()

J
Julian

phpMyAdmin 中,您可以选择多行,然后单击删除操作。您将进入一个列出删除查询的屏幕。它看起来像这样:

https://i.stack.imgur.com/Y8Xgv.png

请取消选中“启用外键检查”复选框,然后单击“是”执行它们。

即使存在 ON DELETE 限制约束,这也将使您能够删除行。


P
Pang

将外键约束设置为 0 不是一个好主意,因为如果这样做,您的数据库将无法确保它不违反参照完整性。这可能导致数据不准确、误导或不完整。

您创建外键是有原因的:因为子列中的所有值都应与父列中的值相同。如果没有外键约束,子行的值可能不在父行中,这会导致数据不准确。

例如,假设您有一个供学生登录的网站,并且每个学生都必须以用户身份注册一个帐户。您有一个用户 ID 表,用户 ID 作为主键;和另一个学生帐户表,以学生 ID 作为列。由于每个学生都必须有一个用户 ID,因此将学生帐户表中的学生 ID 设为引用用户 ID 表中主键用户 ID 的外键是有意义的。如果没有外键检查,一个学生最终可能有一个学生 ID 和没有用户 ID,这意味着一个学生可以在没有成为用户的情况下获得一个帐户,这是错误的。

想象一下,如果它发生在大量数据上。这就是您需要外键检查的原因。

最好找出导致错误的原因。最有可能的是,您尝试从父行中删除而不从子行中删除。在从父行删除之前尝试从子行中删除。


诚然,总会有取舍。
没有人说要永远这样运行它。您关闭约束,批量加载一些数据,然后将其重新打开。没什么大不了的,人们一直都在这样做。
大宗进口是必须的,至少对于性能来说,这是很常见的。有时您只需要恢复数据,然后您就可以进行检查。
这不是问题的答案。
注意,他的问题是如何暂时做到这一点。这在进行某些维护和数据导入时是必需的。当然需要注意的是,您的导入脚本将负责数据完整性。然后,稍后当索引和约束重新打开时,数据库会告诉您是否有问题。