2017-09-21 24 views
1

我有一個具有1.7M記錄表的Mysql系統。這是一個生產系統。它以前是Myisam &非常有彈性,但作爲一個測試,我已經將它轉換爲Innodb(和php腳本),希望它運行得更快,行級鎖定會使它更具彈性。它由30個使用PHP 7 CLI的機器人提供服務。他們每個人都會掃描表中是否需要更新的記錄,然後更新它們,然後繼續作爲團隊的一部分,直到完成任務。他們以40行爲單位執行此操作,這意味着劇本運行約42,500次。Mysql Innodb可以處理重度並行處理

但在測試過程中,我注意到Innodb事務的一些特性,我沒有想到,似乎是showstoppers。在我回滾之前,我想我會問別人的觀點,我是否完全有錯誤或者證明或反駁我的發現。圍繞一個DB調用(所有搜索字段建立索引)跌破發行中心是僞代碼:

update table set busy=$token where condition=true order by id $order limit $units 
if affected rows != $units 
do function to clear 
return 
else do stuff..... 
endif 

前 在MyISAM的結果是,每個機器人需要一個運行在獲得表級鎖,只是排隊,直到他們得到他們。這可能會產生瓶頸,但所有問題都可以在一分鐘內解決。

AFTER 在Innodb下,對於一個機器人來說這個調用是可以的,但是對多用戶工作的任何嘗試都會導致'鎖定超時超時;嘗試重新啓動交易「。 更改wait_timeout/autocommit/tx_isolation沒有區別。也不轉換這一個交易和使用:

begin 
select .... for update 
update 
test 
commit or rollback 

在我看來是:

1 Innodb的產生,即使您沒有設置交易的所有更新的隱式交易。如果這些時間太長,那麼並行處理是不可能的。

2更重要的是,當Innodb鎖定行時,它並不知道它鎖定了哪些行。你可以這樣做:

begin 
select 10 rows where condition=this for update 
update the rows I locked 
commit 

你必須做兩個相同的調用是這樣的:

begin 
select 10 rows where condition=this for update 
update 10 rows where condition=this 
commit 

這是死鎖的robot1配方可以鎖定40行,robot2鎖40種人等但隨後robot1更新了40行,這可能與它剛剛鎖定的行完全不同。這將繼續,直到所有行都被鎖定,並且它們不能回寫到表中。

所以,當我有30個機器人爭奪需要更新的行時,我覺得Innodb對我而言是無用的。這是聰明的,但不夠聰明,以處理重型並行處理。

有什麼想法?

+1

「當Innodb鎖定行時,它不知道'它鎖定了哪些行',只有當你沒有一個好的索引時纔是真的。它鎖定執行查詢時需要查看的所有行(可能還有間隙)。檢查執行計劃,例如一個文件夾,一個全表掃描或類似的東西(和/或將其添加到除了索引和您認爲合適的查詢之外的問題)。檢查你是否啓用了自動提交模式,它在每​​個語句之後提交。它會像'update .... commit ... test ... commit'那樣工作,不像'update ... test ... commit'那樣在僞代碼中。 (但MyISAM也是如此)。 – Solarflare

+0

再次開始測試,並在超時前運行「顯示引擎innodb狀態」。這會給你很多關於當前正在發生的事情的信息。 –

+0

「運行約42,500次」 - 每次?每兩週? –

回答

0

思考這種方法:

SET autocommit = 1; 
Restart: 
$left_off = 0; 
Loop: 
    # grab one item: 
    BEGIN; 
    $id = SELECT id FROM tbl WHERE condition AND id > $left_off 
      ORDER BY id LIMIT 1 FOR UPDATE; 
    if nothing returned, you are end of table, COMMIT and GOTO Restart 
    UPDATE tbl SET busy = $token WHERE id = $id; 
    COMMIT; 
    do stuff 
    UPDATE tbl SET busy = $free WHERE id = $id; -- Release it 
    $left_off = $id; 
Goto Loop 

注:

  • 看來,唯一的原因設置busy是,如果 「做的東西」 掛到行「太長」。我對麼?
  • 我選擇一次鎖定一個 - 不太複雜。
  • $left_off是爲了避免一次又一次掃描大量行。不,OFFSET不是一個可行的選擇。
  • BEGIN覆蓋自動提交。因此,該交易持續到COMMIT
  • 第二個UPDATE以autocommit = 1運行,所以它本身就是一個事務。

請務必定製機器人的數量 - 太少=太慢;太多=太多的爭用。很難預測最佳值。

+0

裏克,是'做東西'可能需要幾分鐘,所以我需要在那段時間鎖定的記錄。但是,我確實需要機器人一次能夠鎖定40條記錄。所以你的方法不適合我的需求。 我已經解決了這個問題,將主表中的相關列放在一個更薄的關係表中。所以現在: \t在此「薄」表 \t其持有的40排它鎖在一個陣列 \t的IDS每個機器人鎖和標記相關行的一環 \t寫回更新到解析通過他們主表並在事務處理過程中清除薄表中的鎖 – user6311673

0

在我測試Innodb v MyIsam期間,我發現當我確實解決了任何爭用問題時,Innodb模型比MyIsam慢了40%。但是,我相信,通過進一步調整,這可以減少,以便它與MyIsam保持一致。

我注意到MyIsam會不定期地排隊'等待表級鎖',這實際上適合我但懲罰了硬盤。 Innodb是一個更加民主的過程,磁盤訪問更加均勻。我暫時將它回滾,但將在幾周內採用我上面評論的調整來追求Innodb版本。

回答我自己的問題:是Innodb可以通過大量調整和合理化數據庫設計來處理重型並行處理。讓人難以置信的是,沒有人回答我的問題,即Innodb記錄鎖定是否意識到它鎖定了哪些記錄。

+0

它鎖定「間隔」(行之間)的時間有點微妙,因此會鎖定更多的行而不是它所需的。 –