2011-05-12 55 views
26

我有一個InnoDB表,需要每10分鐘內從60k到200k記錄中的任何地方重新填充。我們的方法到現在爲止一直如下:MySQL:在事務中截斷表?

  1. 關閉自動提交
  2. 截斷表
  3. 執行SELECT查詢&額外的計算(使用PHP)
  4. 插入新記錄
  5. 提交

雖然通過截斷操作執行後,數據立即刪除,並且沒有lon ger可從用戶界面獲得。對我們的用戶來說,這非常令人不安,即使在大約30秒左右的時間內,腳本遇到提交操作並且表被重新填充。

我想也許我可以在整個交易中將整個操作包括在內,包括 Truncate,並且這可能會減少表格在用戶期間顯示爲空的時間長度。所以我將「SET AUTOCOMMIT = 0」改爲「START TRANSCATION」。

哎呀!這與期望的效果相反!現在TRUNCATE操作仍然發生在腳本的開頭,但是在事務內部實際執行INSERT操作需要很長時間,因此在執行COMMIT操作並且表中的數據再次可用時,已經差不多十分鐘!

什麼可能導致此?實際上,我根本沒有期望有任何改變,因爲我的印象是,啓動交易基本上只會關閉Autocommit?

回答

37

完成此操作的更好方法可能是將數據插入到新表中,然後在兩個表上使用rename以交換它們。交換隻需要一次重命名,這是一個原子操作,這意味着除了顯示新數據外,用戶甚至無法檢測到它發生了。然後可以截斷/刪除舊數據。

+0

這是一個非常有趣的想法。我最初的直覺反應是表面感覺有點ha but,但實際上它們有一定的優雅簡單性,它可​​以完美地解決我的問題。希望我自己想到了。 :) – 2011-05-13 01:32:39

+5

已經過去將近一年了,只是想跟進並提到這就是我們最終做的事情,它就像一個魅力。我們創建新表格,插入一大堆記錄,並在更新完成後立即將它們交換出去 - 最終用戶即時顯示。再次感謝。 – 2012-02-22 00:13:59

+0

謝謝你。一直在用最好的方式來進行批量數據更新,而不需要將數據庫關閉幾秒鐘。這是一個很好的解決方法。 – NickH 2013-06-29 18:47:22

0

從你的描述我不能真正解釋你的時差。唯一想到的是,你實際上並沒有將插入物換成一個事務,而是將其循環。

與SET AUTOCOMMIT = 0的關鍵區別在於,如果已經爲0,則它​​不會執行任何操作,與START TRANSACTION一樣,您將在當前事務中啓動子事務。

44

http://dev.mysql.com/doc/refman/5.1/en/truncate-table.html

根據這個URL,例如MySQL 5.1.32的,TRUNCATE TABLE是DDL和DML不喜歡刪除。這意味着TRUNCATE TABLE將導致在事務塊的中間隱含COMMIT。因此,在需要清空而不是TRUNCATE TABLE的表格上使用DELETE FROM

即使DELETE FROM tblname;也可以回滾。可能需要一段時間才能回滾,因此請確保InnoDB已正確調整以處理事務處理時間以進行此類回滾。

+0

這是很棒的信息,羅蘭多;我非常感謝澄清(和參考)!如果Kibbee沒有給我這樣一個非常簡單的解決方案,我絕對會給你最好的。 – 2011-05-13 01:36:00

+4

@RolandoMySQLDBA請注意,'DELETE FROM table'和'TRUNCATE table'之間的區別並不僅僅在於執行時間。 'TRUNCATE'也將'AUTO_INCREMENT'值重置爲1,但是'DELETE'不會。 – ANTARA 2014-03-24 15:43:56

+1

「,因此請確保InnoDB已妥善調整以處理交易時間以實現此類回滾可能性。」有關如何做到這一點的任何見解? – vcardillo 2015-03-31 04:34:05