我有一个带有1.7M记录表的Mysql系统。这是一个生产系统。以前是Myisam&非常有弹性,但作为一个测试,我已将其转换为Innodb(和PHP脚本),希望它运行得更快,行级锁定将使其更具弹性。它由30个使用PHP 7 CLI的机器人提供服务。他们每个人都会扫描表格以查找需要更新的记录,然后更新它们,然后继续作为团队的一部分,直到工作完成。他们以40行的方式执行此操作,这意味着脚本运行大约42,500次。
但是在测试过程中,我注意到Innodb交易的一些功能,我没有想到,似乎是showstoppers。在我回滚之前,我想我会问别人他们的观点,我是否完全弄错了,或证明或反驳我的发现。下面围绕一个db调用(所有搜索字段都已编入索引)的问题是伪代码:
update table set busy=$token where condition=true order by id $order limit $units
if affected rows != $units
do function to clear
return
else do stuff.....
endif
在 在Myisam下,结果是每个机器人都会在获取表级锁定时运行,然后排队直到获得它们。这可能会产生瓶颈,但所有这些都会在一分钟内得到解决。
在 在Innodb下,一个机器人的呼叫是可以的,但任何多用户工作的尝试都会导致超过锁定等待超时;尝试重新启动交易'。 更改wait_timeout / autocommit / tx_isolation没有任何区别。也不会将此转换为交易并使用:
begin
select .... for update
update
test
commit or rollback
在我看来:
1即使您没有设置交易,Innodb也会为所有更新创建隐式交易。如果这些花费的时间太长,则无法进行并行处理。
2更重要的是,当Innodb锁定行时,它并不知道'它锁定的行。你不能这样做:
begin
select 10 rows where condition=this for update
update the rows I locked
commit
你必须做两个相同的调用:
begin
select 10 rows where condition=this for update
update 10 rows where condition=this
commit
这是一个死锁的配方,因为robot1可以锁定40行,robot2可以锁定其他40个等等,然后机器人1然后更新40行,这些行可能与它刚刚锁定的行完全不同。这将继续,直到所有行都被锁定,并且它们无法写回到表中。
因此,在我有30个机器人竞争需要更新的行块的情况下,我认为Innodb对我的目的来说是无用的。它很聪明,但不够聪明,无法处理繁重的并行处理。
任何想法......
答案 0 :(得分:0)
考虑这种方法:
SET autocommit = 1;
Restart:
$left_off = 0;
Loop:
# grab one item:
BEGIN;
$id = SELECT id FROM tbl WHERE condition AND id > $left_off
ORDER BY id LIMIT 1 FOR UPDATE;
if nothing returned, you are end of table, COMMIT and GOTO Restart
UPDATE tbl SET busy = $token WHERE id = $id;
COMMIT;
do stuff
UPDATE tbl SET busy = $free WHERE id = $id; -- Release it
$left_off = $id;
Goto Loop
注意:
busy
的唯一原因是“do stuff”挂在行上“太长”。我是对的吗?$left_off
是为了避免一次又一次地扫描大量行。不,OFFSET
不是一个可行的选择。BEGIN
会覆盖自动提交。因此,交易将持续到COMMIT
。UPDATE
,因此它本身就是一个事务。一定要定制机器人的数量 - 太少=太慢;太多=太多争用。很难预测最佳值。
答案 1 :(得分:0)
在我对Innodb v MyIsam的测试中,我发现当我解决任何争用问题时,Innodb模型比MyIsam慢40%。但是,我相信通过进一步调整可以减少它,使其与MyIsam相提并论。
我做了什么注意到MyIsam会无限制地排队等待桌级锁定,这实际上适合我,但惩罚了硬盘。而Innodb是一个更民主的过程,磁盘访问更加均衡。我暂时回滚了它,但是我会在几周内通过上面评论的调整来追求Innodb版本。
回答我自己的问题:是的Innodb可以通过大量调整和合理化数据库设计来处理繁重的并行处理。令人失望的是,没有人回答我关于Innodb记录锁定是否知道它锁定了哪些记录的问题。