如何订购复合索引以防止插入死锁?

时间:2017-09-15 14:38:17

标签: python mysql mariadb innodb

我有一个mysql(实际上是MariaDB 5.5.52)数据库大致描述如下:

CREATE TABLE table1 (
    id INT NOT NULL AUTOINCREMENT, 
    col1 INT, 
    col2 VARCHAR(32), 
    col3 VARCAHR(128), 
    PRIMARY KEY (ID), 
    UNIQUE KEY index1 (col1, col2, col3)
);

列中有更多列,但所有列都位于UNIQUE键内,表中没有其他键。

我运行插入此数据库的python脚本的多个线程。每个线程使用mysql.connector的executemany(例如

)执行大约100-1000次插入
ins_string = "INSERT IGNORE INTO table1 ({0}) VALUES ({1});"
cursor.executemany(ins_string.format(fields, string_symbols), values)

我遇到了一致的死锁问题。我假设这些问题是由于每个线程基于生成我的python列表values的顺序以某种半随机顺序在table1的行之间锁定而引起的。这在一定程度上通过测试验证;当我使用24个线程从头开始构建新数据库时,每个executemany()语句的死锁率是> 80%,但到数据库中有一百万+行时,死锁率几乎为零。

我曾考虑过死锁是线程竞争AUTOINCREMENT的结果,但在默认的InnoDB'连续'锁定模式下,似乎不会发生这种情况。在INSERT结束之前,每个线程都应该获得table level lock。但是,AUTOINCREMENT和INSERT锁相互作用的方式对我来说很困惑,所以如果我有这个错误,请告诉我。

因此,如果问题是由唯一键的随机排序引起的,我需要一些方法在python中对insert语句进行排序,然后再将它们传递给MySql。索引在某种程度上由MySql进行哈希处理,然后进行排序。我如何在python中复制散列/排序?

我在这里询问解决问题的方法,但如果你发现我的诊断错误,请再次告诉我。

1 个答案:

答案 0 :(得分:0)

为什么有ID,因为您有UNIQUE密钥可以提升为PRIMARY

无论如何,在构建(col1, col2, col3)之前,对executemany上的批量插入行进行排序。

如果这还不够,那么减少每个executemany中的行数。 100行在理论上最好的10%左右。如果100降低了下面的死锁频率,比如10%,那么你可能非常接近于由于重放死锁而导致的批量加载速度和减速之间的最佳平衡。

你有多少个CPU内核?

你还没有向我们展示其他指数吗? 每个 UNIQUE索引都会影响此问题。非唯一索引不是问题。请提供完整的SHOW CREATE TABLE