Mysql死锁解释



我需要一些帮助来解决我面临的死锁情况。

下面是我的一个测试脚本,它模拟了我所遇到的问题我有一个标签表,每个请求,可能会插入/更新很多条目,所有这些都在一个事务中。

我知道死锁的发生是因为很多线程锁定了相同的条目,我想要一些关于如何避免它们的反馈

我正在运行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();
?>

令人惊讶的是,即使使用InnoDB也可能发生死锁。这是为什么呢?

聚集索引(内部称为gen_clust_index)可以在涉及批量插入的事务中间间歇性地锁定。事务中insert的有趣之处与InnoDB日志文件有很大关系。插入的数据行的前一个状态是不存在的行。这种表示不存在的行的MVCC数据将被记录在重做日志中,以支持回滚、脏读取等操作。执行批量插入将创建许多不存在的行用于回滚。

我曾经在DBA StackExchange上遇到过一个人关于连续更新的死锁情况的一系列问题。以下是这些问题和我的回答:

  • 如果按顺序执行,这两个查询会导致死锁吗?
  • innodb状态日志中出现死锁故障
  • 查询偶尔变慢的原因?

您可能必须尝试在没有事务的情况下执行批量插入,使用以下任何一种:

  • 在每次INSERT后执行COMMIT
  • 使用自动提交= 1

如果你必须在一个事务中插入,试着增加InnoDB日志文件的大小和大容量插入缓冲区:

步骤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]

step04) service mysql start

mysql启动时,会重新创建ib_logfil0和ib_logfile1

试试吧!!我希望这对你有帮助。

UPDATE 2011-10-31 12:43 EDT

我刚刚在DBA StackExchange 3天前回答了这样一个问题

最新更新