REPLACE INTO

时间:2015-06-13 04:10:06

标签: mysql database innodb deadlock

我想更新mysql中的统计数。

SQL如下:

REPLACE INTO `record_amount`(`source`,`owner`,`day_time`,`count`) VALUES (?,?,?,?)

架构:

CREATE TABLE `record_amount` (
   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
   `owner` varchar(50) NOT NULL ,
   `source` varchar(50) NOT NULL ,
   `day_time` varchar(10) NOT NULL,
   `count` int(11) NOT NULL,
   PRIMARY KEY (`id`),
   UNIQUE KEY `src_time` (`owner`,`source`,`day_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

但是,它在多进程运行中引起了DEADLOCK异常(即Map-Reduce)。

我在线阅读了一些材料并对这些锁感到困惑。我知道innodb使用行级锁。我可以使用table-lock来解决业务问题,但这有点极端。我找到了一些可能的解决方案:

  1. REPLACE INTO更改为与SELECT id FOR UPDATEUPDATE
  2. 进行的交易
  3. REPLACE INTO更改为INSERT ... ON DUPLICATE KEY UPDATE
  4. 我不知道哪个更实用,更好。有人可以解释它或提供一些链接供我阅读和学习吗?谢谢!

1 个答案:

答案 0 :(得分:-1)

您是在构建汇总表,一次构建一个源行吗?并有效地做UPDATE ... count = count+1?扔掉代码然后重新开始。 MAP-REDUCE就像在图钉上使用大锤一样。

INSERT INTO summary (source, owner, day_time, count)
    SELECT source, owner, day_time, COUNT(*)
        FROM raw
        GROUP BY source, owner, day_time
    ON DUPLICATE KEY UPDATE count = count + VALUES(count);

单个语句大致相同,它将以虚拟磁盘I / O速度完成所有工作。没有SELECT ... FOR UPDATE。没有死锁。没有多线程。等

进一步改进:

  • 摆脱AUTO_INCREMENT;将UNIQUE变为PRIMARY KEY
  • day_time - 是DATETIME截断到一小时? (或类似的东西。)使用DATETIME,您将有更多的查询灵活性。

进一步讨论,请详细说明源数据(`CREATE TABLE,行数,处理频率等)和其他细节。如果这是一个带有Summary表的数据仓库应用程序,我可能会有更多建议。

如果数据来自文件,请LOAD DATA将其拖放到临时表raw中,以便上述INSERT..SELECT可以正常工作。如果它的大小可管理,请raw Engine=MEMORY以避免任何I / O.

如果您有多个Feed,my high-speed-ingestion blog讨论了如何在没有任何死锁的情况下拥有多个线程。