使用FK更新行时的MySQL性能

使用FK更新行时的MySQL性能,mysql,Mysql,我有两张桌子 spies | --------- | id | PK weapon_id | FK name | weapons --------- | id | PK name | 我试图澄清这两个SQL更新之间是否存在差异(使用MySQL innoDB时) 问题1: 更新间谍集名称='Bond',武器id=1,其中id=1 或 问题2: UPDATE spies SET name='Bond',其中id=1 我听说,当

我有两张桌子

spies     | 
--------- | 
id        | PK
weapon_id | FK
name      |   


weapons
--------- |
id        | PK
name      | 
我试图澄清这两个SQL更新之间是否存在差异(使用MySQL innoDB时)

问题1:

更新间谍集名称='Bond',武器id=1,其中id=1

问题2:

UPDATE spies SET name='Bond',其中id=1

我听说,当使用FK更新行时,会在父级上创建只读锁(不确定这是否是正确的术语)


使用查询2是否可以避免父表上的锁定?

为什么不运行此查询的解释并亲自检查它

所以,让我们跑吧

EXPLAIN UPDATE spies SET name = 'Bond', weapon_id = 1 WHERE id = 1\G
并检查此查询扫描的行数,检查部分并查看其扫描的行数

对下面的一个也做同样的事情

EXPLAIN UPDATE spies SET name = 'Bond' WHERE id = 1\G
现在,说到您的问题,INNODB将锁定您对表中每一行所做的每一次更新。但请记住,这是一个行级锁定

因此,为了回答您的问题,如果行与表相同,则使用外键或不使用外键更新行不会产生任何影响

如果它是一个不同的行或不同的表,它将产生不同的效果


考虑以下模式: (为了方便起见,Rem stmts保留在中):

现在,我们有两个进程,P1和P2。最好测试P1可能是MySQL工作台,P2是MySQL命令行窗口。换句话说,您必须将其设置为单独的连接和权限。您必须有一双细致的眼睛,以适当的方式一步一步地运行这些程序(在下面的叙述中描述),并查看它对其他流程窗口的影响

考虑以下查询,请记住,未包装在显式事务中的mysql查询本身就是隐式事务。但在下文中,我明确表示:

问题1:

问题2:

问题3:

第四题:

问题5(hodge podge的问题):

叙述的 Q1:当P1开始Q1并到达位置2时,它在id=1行的表武器和间谍中获得了排他行级别的更新锁(总共2行,每个表中1行)。P2开始运行Q3,到达place1,但在place2上阻塞,并且只有在P1开始调用COMMIT时才被释放,这就证明了这一点。我刚才所说的关于P2运行第三季度的内容与P2运行第四季度的内容相同。总之,在P2屏幕上,place2冻结,直到P1提交

关于隐式事务的再次说明。您真正的Q1查询将以非常快的速度执行此操作,然后执行隐式提交。然而,前面的一段将其分解,如果您运行的例程花费的时间更多

Q2:当P1开始Q2并到达位置2时,它在id=1行的表武器和间谍中获得了排他行级别的更新锁(总共2行,每个表中1行)。但是,P2在Q3拦截
武器时没有问题,但P2在第2
间谍处运行Q4时有拦截问题

因此,Q1和Q2之间的差异可以归结为MySQL知道FK索引与更新中的列无关,手册在下面的Note1中说明了这一点

当P1运行Q1时,P2对只读非锁获取Q5类型的查询没有问题。唯一的问题是P2在隔离级别的基础上看到了什么数据格式副本

注1:来自MySQL手册页面,标题为:

如果在表上定义了外键约束,则任何insert、update、, 或删除需要选中约束条件的集合 共享记录级别锁定它查看的记录以检查 约束。InnoDB还在以下情况下设置这些锁: 约束失效

以上就是为什么Q2:的行为使得P2可以自由地执行更新或获取
武器上的更新独占瞬时锁。这是因为引擎没有使用P1对武器id执行更新,因此该表中没有行级锁

要将这一点拉回50000英尺,人们最关心的是隐式事务(没有启动/提交的事务)或提交前显式事务中锁的保持时间。从理论上讲,可以无限期地禁止对等进程获取其更新需求。但每次尝试获取该锁都受其设置的控制。这意味着,默认情况下,在大约60秒后超时。要查看您的设置,请运行:

select @@innodb_lock_wait_timeout;

对我来说,现在是50秒。

总之,你的意思是,为了避免在武器表上有一个独占的更新锁,在spies表上进行更新而不指定武器id应该避免这种情况。你想加入我的聊天室吗,因为这可能会持续一段时间,谁知道呢。这个答案似乎与第一个答案相矛盾。所以我不确定哪一个是正确的。您的意思是,无论在UPDATE语句中是否指定了武器id,由于spies表上的FK约束,武器表将始终具有显式更新锁。是这样吗?
START TRANSACTION;
-- place1
UPDATE spies SET name = 'Bond', weapon_id = 1 WHERE id = 1;
-- place2
COMMIT;
START TRANSACTION;
-- place1
UPDATE spies SET name = 'Bond' WHERE id = 1;
-- place2
COMMIT;
START TRANSACTION;
-- place1
SELECT id into @mine_to_use from weapons where id=1 FOR UPDATE; -- place2
-- place3
COMMIT;
START TRANSACTION;
-- place1
SELECT id into @mine_to_use from spies where id=1 FOR UPDATE; -- place2
-- place3
COMMIT;
SELECT * from weapons;
SELECT * from spies;
select @@innodb_lock_wait_timeout;