我想更新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来解决业务问题,但这有点极端。我找到了一些可能的解决方案:
REPLACE INTO
更改为与SELECT id FOR UPDATE
和UPDATE
REPLACE INTO
更改为INSERT ... ON DUPLICATE KEY UPDATE
我不知道哪个更实用,更好。有人可以解释它或提供一些链接供我阅读和学习吗?谢谢!
答案 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
。DATETIME
截断到一小时? (或类似的东西。)使用DATETIME
,您将有更多的查询灵活性。进一步讨论,请详细说明源数据(`CREATE TABLE,行数,处理频率等)和其他细节。如果这是一个带有Summary表的数据仓库应用程序,我可能会有更多建议。
如果数据来自文件,请LOAD DATA
将其拖放到临时表raw
中,以便上述INSERT..SELECT
可以正常工作。如果它的大小可管理,请raw
Engine=MEMORY
以避免任何I / O.
如果您有多个Feed,my high-speed-ingestion blog讨论了如何在没有任何死锁的情况下拥有多个线程。