是否有可能暂时禁用MySQL中的约束?
我有两个Django模型,每个模型都有一个ForeignKey到另一个。 由于ForeignKey约束,删除模型的实例会返回错误:
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可能是一个暂时的东西,如果它确实知道,那就会引起恐慌。
你想做什么很奇怪。但是你使用的是哪个数据库?
@andrefsp:我正在使用MySQL。我将编辑我的问题以添加它。
如果您将其永久修改为ON DELETE SET NULL而不是禁用约束,该怎么办?这将完成类似的事情,你不必打开和关闭键检查。
@dnagirl:确实会更好。我怎样才能做到这一点?
你应该按照@dnagirl的要求去做。它的方式更合理,并且确保您不会以非常讨厌的方式处理数据。像你想做的那样玩它可能会导致严重的完整性和一致性问题。
试试DISABLE KEYS或
SET FOREIGN_KEY_CHECKS=0;
确保
SET FOREIGN_KEY_CHECKS=1;
后。
这是为mysql整体设置还是仅为该会话设置的东西?
我相信这是每次会议。
stackoverflow.com/questions/8538636/…
serverfault.com/questions/291100/… ,另请注意,Innodb不能disable keys
我可以为单个表禁用FOREIGN_KEY_CHECKS吗?
@Pacerier从阅读中看,它似乎可以,但仅适用于单个会话。
要全局关闭外键约束,请执行以下操作:
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
尝试UPPERCASE @MikeB
@berniey没有运气。不过没关系。我使用alter语句暂时禁用外键约束。
@MikeB,我认为它与您用来发出命令的工具有关(它与myqsl命令行工具一起使用)。我一直在v5.5和5.6上使用该命令,它工作正常。文档建议甚至适用于v5.7。 dev.mysql.com/doc/refman/5.7/en/server-system-variables.html。此外,案件无关紧要(请原谅我之前的建议)
请注意,如果连接到在发出全局查询之前启用了外键检查的MySQL,则会保留外键检查的当前会话状态。即SET GLOBAL FOREIGN_KEY_CHECKS=0; SELECT @@FOREIGN_KEY_CHECKS;将返回1,直到您重新连接以开始新会话
我通常只在我要截断表时才禁用外键约束,因为我不断回到这个答案,这是为了将来我:
SET FOREIGN_KEY_CHECKS=0;
TRUNCATE TABLE table;
SET FOREIGN_KEY_CHECKS=1;
不是禁用约束,而是永久地将其修改为ON DELETE SET NULL。这将完成类似的事情,你不必打开和关闭键检查。像这样:
请阅读此内容(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,并在脏工作完成后将其重新放回。除此之外它可能会锁定写表。
改变远程列类型时不会破坏引用吗? (似乎我的客户端将修改后的临时表重命名为原始表名。)
要全局关闭外键约束:
SET GLOBAL FOREIGN_KEY_CHECKS = 0;
并用于活动外键约束
SET GLOBAL FOREIGN_KEY_CHECKS = 1;
phpmyadmin的一个非常简单的解决方案:
在表格中,转到SQL选项卡
编辑要运行的SQL命令后,GO旁边会出现一个复选框,名为"启用外键检查"。
取消选中此复选框并运行SQL。它将在执行后自动重新检查。
谢谢!确实,解决方案SET FOREIGN_KEY_CHECKS=0; ..... SET FOREIGN_KEY_CHECKS=1;在PHPMyAdmin中对我不起作用,因为我忘了取消选中"启用外键检查"复选框。在PHPMyAdmin中,您可以跳过这些SET命令,只需取消选中该复选框即可。
如果键字段可以为空,那么您也可以在尝试删除它之前将该值设置为null:
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()
对我来说,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抛出警告,运行DISABLE KEYS命令时InnoDB引擎没有此选项。
这确实有效,没有改变表它也不适合我
在phpMyAdmin中,您可以选择多行,然后单击删除操作。您将进入一个列出删除查询的屏幕,您可以取消选中外键检查,然后单击是以执行它们。
即使存在ON DELETE限制约束,这也可以删除行。
将外键约束设置为0并不是一个好主意,因为如果这样做,您的数据库将无法确保它不会违反参照完整性。这可能会导致数据不准确,误导或不完整。
您出于某种原因创建外键:因为子列中的所有值都应与父列中的值相同。如果没有外键约束,子行可以具有不在父行中的值,这将导致不准确的数据。
例如,假设您有一个供学生登录的网站,每个学生都必须以用户身份注册帐户。您有一个用户ID表,用户ID作为主键;和另一个学生帐户表,学生ID为专栏。由于每个学生都必须拥有用户ID,因此从学生帐户表中将学生ID作为引用用户ID表中的主键用户ID的外键是有意义的。如果没有外键检查,学生可能最终拥有学生ID而没有用户ID,这意味着学生可以在不是用户的情况下获得帐户,这是错误的。
想象一下,如果它发生在大量数据上。这就是你需要外键检查的原因。
最好找出导致错误的原因。您很可能尝试从父行删除而不从子行中删除。在从父行删除之前尝试从子行中删除。
没错,总会有一个权衡。
没人说要永远这样运行它。您关闭约束,批量加载某些数据,然后重新打开它。没什么大不了的,人们总是这样做。
对于批量进口是必要的,至少对于性能来说,它是非常普遍的。有时您只需要恢复数据,然后您可以进行检查。
这不是问题的答案。
请注意,他的问题是暂时如何做到这一点。执行某些维护和数据导入时需要这样做。需要注意的是,导入脚本会对数据完整性负责。然后,稍后当重新打开索引和约束时,db将告诉您某些内容是否已损坏。
你有没有用过phpMyAdmin?