我需要一些帮助解决我面临的僵局。
以下是我的模拟我遇到的问题的测试脚本 我有一个标签表,根据请求,可以在一个事务中插入/更新大量条目。
我知道死锁的发生是因为很多线程锁定了相同的条目,我希望得到一些关于如何避免它们的反馈
我正在运行ab -n 100 -c 5 http://localhost/script.php
这个表
CREATE TABLE `tags`
(
`id` INT(8) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(40) COLLATE utf8_unicode_ci DEFAULT NULL,
`weight` INT(8) DEFAULT NULL,
`type` ENUM('1','2','3') COLLATE utf8_unicode_ci DEFAULT NULL,
`modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `tag_name` (`name`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
<?php
function go() {
$db = DB::getInstance();
$db->start_transaction();
$tgs = array('electricity', 'emergency', 'trees', 'New Jersey', 'Canada funnelled');
foreach($tgs as $tg) {
$arr_tags = array(
'name' => $tg,
'weight' => '0',
'type' => TagTable::PRIMARY
);
$tag_instance = new Tag($arr_tags);
$tag_instance->save(true);
// the save method executes a query like the below
// INSERT INTO tags (weight, type, modified, id, name) VALUES(0, "1", NULL, NULL, "$tag") ON DUPLICATE KEY UPDATE weight = weight+1;
}
$db->commit();
}
go();
?>
答案 0 :(得分:2)
令人惊讶的是,即使使用InnoDB也可能发生死锁。原因是什么?
clustered index (known internally as the gen_clust_index)可以在涉及批量INSERT的事务中间歇性地锁定。关于事务中INSERT的有趣之处与InnoDB日志文件有很大关系。 INSERT的一行数据的先前状态是不存在的行之一。表示不存在的行的此类MVCC数据将记录在重做日志中,以支持回滚,脏读和类似这样的事情。执行批量INSERT将创建许多这些不存在的行以进行回滚。
我曾经在DBA StackExchange中遇到过一系列有关连续UPDATE死锁情况的问题。以下是这些问题和我的答案:
您可能必须尝试执行批量INSERT而不使用以下任一项的事务:
如果您必须在事务中拥有INSERT,请尝试增加InnoDB日志文件的大小和bulk insert buffer:
步骤01)将此行添加到/etc/my.cnf
[mysqld]
bulk_insert_buffer_size=256M
innodb_log_file_size=2047M
步骤02)service mysql stop
步骤03)rm -f /var/lib/mysql/ib_logfile[01]
步骤04)service mysql start
在启动mysql期间,重新创建ib_logfile0和ib_logfile1
尝试一下!!!我希望它有所帮助。
UPDATE 2011-10-31 12:43 EDT
I just answered a question like this in the DBA StackExchange 3 days ago