INSERT 中的死锁 ... ON DUPLICATE KEY UPDATE

Joe*_*ris 7 deadlock mysql-5.6 bulk-insert

我们有一个这样定义的表:

CREATE TABLE ipsum ( 
    id char(40) NOT NULL, 
    source char(40) NOT NULL, 
    ip_address varbinary(16) NOT NULL, 
    port smallint(5) unsigned NOT NULL, 
    percentage decimal(5,2) NOT NULL DEFAULT '0.00', 
    first_date datetime NOT NULL, 
    last_date datetime NOT NULL, 
    p0 tinyint(1) NOT NULL DEFAULT '0',
    p1 tinyint(1) NOT NULL DEFAULT '0', 
    blocked tinyint(1) NOT NULL, 
    created datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    country varchar(100) DEFAULT NULL, 
    continent varchar(100) DEFAULT NULL, 
    note varchar(100) DEFAULT NULL, 
    PRIMARY KEY (id), 
    KEY idx_first_seen_peer (first_date), 
    KEY idx_last_seen_peer (last_date), 
    KEY ipsum (source,ip_address,port) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 
Run Code Online (Sandbox Code Playgroud)

我们正在批量插入这个表,一次最多 15,000 条记录。插入的结构如下:

INSERT INTO ipsum (id, source, ip_address, port, percentage, first_date, last_date, p0, p1, country, continent, note, blocked) 
VALUES {{ 15000 legitimate values here sorted alphabetically by the id field }} 
ON DUPLICATE KEY UPDATE 
p0 = p0 OR VALUES(p0), 
p1 = p1 OR VALUES(p1), 
last_date = GREATEST(last_date, VALUES(last_date)), 
first_date = LEAST(first_date, VALUES(first_date)), 
percentage = GREATEST(percentage, VALUES(percentage));
Run Code Online (Sandbox Code Playgroud)

VALUES集合中的记录已按 id 字母顺序排序。

当我们在运行多个查询实例的情况下达到非常高的输入率时,我们开始看到死锁:

错误:ER_LOCK_DEADLOCK:尝试获取锁时发现死锁;尝试重新启动事务]

没有对表执行其他语句——只有如上所述的插入。

如何修改插入查询以防止死锁?

RMa*_*his 0

尽管“show processlist”可能会将所有进程显示为睡眠状态,但这并不一定意味着该表没有被另一个进程锁定。

 show open tables where name_locked=1;

 select *
   from performance_schema.table_lock_waits_summary_by_table
  where object_schema=@db
    and object_name=@tab
 \G
Run Code Online (Sandbox Code Playgroud)