我正在寻找一种为一个线程显式选择一个表行的方法。我写了一个爬虫,它可以处理大约 50 个并行进程。每个进程都必须从表中取出一行并进行处理。
CREATE TABLE `crawler_queue` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`url` text NOT NULL,
`class_id` tinyint(3) unsigned NOT NULL,
`server_id` tinyint(3) unsigned NOT NULL,
`proc_id` mediumint(8) unsigned NOT NULL,
`prio` tinyint(3) unsigned NOT NULL,
`inserted` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `proc_id` (`proc_id`),
KEY `app_id` (`app_id`),
KEY `crawler` (`class_id`,`prio`,`proc_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
现在我的流程执行以下操作:
- 启动数据库事务
- 做一个选择
SELECT * FROM crawler_queue WHERE class_id=2 AND prio=20 AND proc_id=0 ORDER BY id LIMIT 1 FOR UPDATE
- 然后用
UPDATE crawler_queue SET server_id=1,proc_id=1376 WHERE id=23892
- 提交事务
这应该有助于没有其他进程可以获取尚未处理的行。在精选节目上做解释
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE crawler_queue ref proc_id,crawler proc_id 3 const 617609 Using where
但是这些进程似乎会导致并行度过高,因为有时我会在日志中看到两种类型的错误/警告(每 5 分钟左右):
mysqli::query(): (HY000/1205): Lock wait timeout exceeded; try restarting transaction (in /var/www/db.php l
ine 81)
mysqli::query(): (40001/1213): Deadlock found when trying to get lock; try restarting transaction (in /var/www/db.php line 81)
我的问题是:谁能指出我正确的方向来最小化这些锁定问题?(在生产状态下,并行度会比现在高 3-4 倍,所以我假设会有更多的锁定问题)
我修改为按提示SELECT
使用索引。我现在的问题是 lockwait 超时了(死锁消失了)。crawler
USE INDEX(crawler)
EXPLAIN
现在显示USE INDEX()
(行数更高,因为表现在包含更多数据):
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE crawler_queue ref proc_id,crawler crawler 5 const,const,const 5472426 Using where