2014-03-19 162 views
4

我有一個表超過1.6億的條目,其中有一個錯誤的表引擎,所以我要改變引擎。 當我這樣做沒有任何準備,我得到一個錯誤,由於我的緩衝區的大小,因爲有太多的行鎖將一個表鎖鎖定行鎖定

mysql> ALTER TABLE foobar ENGINE=MyISAM; 
ERROR 1206 (HY000): The total number of locks exceeds the lock table size 

我現在想這個動作之前鎖定整個表,後來解開整個表的。

mysql> LOCK TABLES foobar WRITE; 

我的問題:請問MySQL服務器通知鎖定表已經是活動的,並跳過行級鎖或有它鎖定表,現在也可以再次鎖定每一行,我會再次遇到同樣的錯誤?

我也打開任何其他sugestions如何改變這麼大的(和更大)表的發動機的最快方法:)

+1

檢查pt-online-schema-change工具。它也應該解決你的問題。但MyISAM ......你不關心你的數據,是嗎? :) – akuzminsky

+0

感謝您對該工具的建議!我更喜歡在沒有任何第三方工具的情況下更改引擎,但也許沒有其他方法可以解決此問題。順便說一句:每個工具都能完成工作;) - MyISAM也是如此。所以要回答你的問題:不,在這種情況下,我實際上並沒有,它實際上是一個緩存表,但無論如何...問題是更多的關於後臺進程和理解,如果MySQL表跳過行鎖定,如果表鎖定已經激活: ) – Preexo

回答

3

可以運行一個實驗:

在第一會話中運行:

mysql> LOCK TABLE foobar WRITE; 
mysql> ALTER TABLE foobar ENGINE=MyISAM; 

在第二會話(即打開第二個終端窗口),運行:

mysql> SHOW ENGINE INNODB STATUS\G 

向下在TRANSACTIONS部分,您會發現正在進行ALTER線程:

---TRANSACTION 69638, ACTIVE 45 sec fetching rows 
mysql tables in use 1, locked 1 
14626 lock struct(s), heap size 1898936, 5145657 row lock(s) 

哇!它創建了許多單獨的行鎖,儘管實際上是LOCK TABLE。

(這只是一個例子,你會看到行鎖的數量隨時間增加爲ALTER TABLE致力於通過你的表)


所以你需要保證空間的大量行鎖。

https://dev.mysql.com/doc/refman/5.6/en/innodb-error-codes.html說:

  • 1206(ER_LOCK_TABLE_FULL)

    鎖的總數超過存儲器的InnoDB致力於管理鎖的量。爲避免此錯誤,增加innodb_buffer_pool_size的值。在個別應用程序中,解決方法可能是將大操作分解爲更小的部分。例如,如果對於較大的INSERT發生錯誤,請執行幾個較小的INSERT操作。

(重點煤礦)

又讀How much memory Innodb locks really take?

Innodb的行級鎖是通過具有特殊的鎖表,坐落在每個哈希小記錄分配的緩衝池實現並且可以設置鎖定在該頁面上的每一行。這在理論上可以給出每行少至幾位的開銷。

因此,鎖定1.6億行需要鎖表中大約60-80MB的空間。您的緩衝池可能太小而無法容納。

在MySQL 5.1.27及更早版本中,InnoDB緩衝池的默認大小僅爲8MB。 MySQL 5.1.28中默認增加到128MB。


回覆您的評論:

每一個工具,它的工作EY) - 也是如此的MyISAM

MyISAM不支持原子性,一致性,隔離性和耐久性。除此之外,這很好。 :-)

+0

感謝您的幫助!我的服務器版本是'5.5.35-0 + wheezy1-log',所以應該有足夠的...我剛剛分配了'1G',讓我們看看這將如何工作。關於評論:是的,我們真的不需要'ACID'這個表,我們甚至可以清空它並重建緩存,如果這樣做不起作用,所以對我們來說MyISAM很棒:) – Preexo

+0

好吧, t需要事務,並且數據在損壞時很容易重建,而且您喜歡[MyISAM性能更差](http://www.mysqlperformanceblog.com/2007/01/08/innodb-vs-myisam-vs- falcon-benchmarkmarks-part-1 /),然後去做! –

+0

比爾,你是否先嚐試auto_commit = 0,以便表鎖不會立即釋放? –

1

通常情況下,如果你的InnoDB緩衝池不夠大,無法容納一行鎖定表中的所有行(有時需要),則增加InnoDB緩衝池大小(innodb_buffer_pool_size)。

嘗試將您的innodb_buffer_pool_size增加到128 MB。

如果仍有問題,可以隨時嘗試創建新的MyISAM表,然後執行INSERT INTO ... SELECT FROM ...將您的數據從InnoDB表複製到MyISAM表中。您可以複製塊中的行以減少行鎖。

+0

感謝您的建議,將數據從舊錶複製到新表(使用正確的引擎)是下一步,我會嘗試,如果'ALTER'仍然失敗。我只是認爲mysql在內部執行相同的操作(通過'ALTER'上的臨時表進行復制),因此手動執行操作的位置......但也許我錯了,這就是解決方案;明天再見。 – Preexo

+0

InnoDB在'INSERT INTO ... SELECT FROM ...'期間在源表的行上創建* shared *鎖。例如,這可能會導致從屬服務器上的複製線程被阻塞,而您將很多行插入臨時表中。 –