2017-09-15 42 views
0

我有一個MySQL大致描述如下(實際上MariaDB的52年5月5日)數據庫:如何訂購複合索引以防止插入死鎖?

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腳本的多個線程。每個線程執行100-1000左右使用插入mysql.connector的executemany這樣

ins_string = "INSERT IGNORE INTO table1 ({0}) VALUES ({1});" 
cursor.executemany(ins_string.format(fields, string_symbols), values) 

我碰上一致的死鎖問題。我認爲這些問題是由於每個線程根據我的Python列表values的生成順序以某種半隨機順序鎖定在table1的行之間所致。這有點通過測試驗證;當我使用24個線程從頭開始構建新的數據庫時,每個executemany()語句的死鎖率大於80%,但到數據庫中有100多行時,死鎖率幾乎爲零。

我認爲僵局是線程AUTOINCREMENT競爭的結果的可能性,但在默認的InnoDB「連續」鎖定模式,它似乎並不像這應該發生。每個線程都應該得到table level lock直到INSERT結束。然而,AUTOINCREMENT和INSERT鎖的交互方式讓我感到困惑,所以如果我有這個錯誤,請讓我知道。

因此,如果問題是由唯一鍵的隨機排序ISH造成的,我需要將它們傳遞到MySql之前訂購的蟒蛇insert語句的一些方法。該索引由MySql以某種方式散列,然後進行排序。我如何可以在python中複製哈希/排序?

我想諮詢一下解決我的問題就在這裏的診斷,但如果你看到我的診斷是錯誤的,再次,請讓我知道。

回答

0

爲什麼要有ID,因爲您有一個UNIQUE密鑰可以升級到PRIMARY

無論如何,在構建executemany之前,對(col1, col2, col3)上的批量插入行進行排序。

如果不是足夠大,則降低在每個executemany的行數。 100行在理論最佳值的10%左右。如果100降低了低於10%的死鎖頻率,那麼由於重放死鎖,您可能非常接近批量加載速度和減速之間的最佳平衡。

你有多少個CPU核心?

您沒有顯示我們還有其他的指標? 每個UNIQUE指數因素導入這個問題。非唯一索引不是問題。請提供完整的SHOW CREATE TABLE

+0

有8列,所有這些列都在UNIQUE索引中;否則就是完整的'CREATE TABLE'語句。 'id'列存在作爲各種子表的外鍵。我從來沒有運行比CPU核心更多的線程,通常我在48核心服務器上,而限制到24個線程或更少(還有其他進程正在進行)。 – kingledion

+0

@kingledion - 行;這些答案看起來很合理因此,我投票選擇(1)預先排序executemany的行和(2)更小的批次。少於24條的線程可能有助於避免死鎖,但可以減少工作量 - 無法預測它是否值得做。什麼版本的MySQL?舊版本在24個線程中效率低下。 –

+0

這是MariaDB 5.5.52。我想我應該提到它是MariaDB ...什麼構成了「舊」版本? – kingledion