2013-11-26 48 views
1

我有一個多線程客戶端/服務器系統,客戶端連續不斷地向存儲在特定表中的服務器發送數據,但這些數據只是重要的幾天之後,所以在超過使用期限後將被刪除。
服務器是用J2SE編寫的,數據庫是MySQL,我的表使用InnoDB引擎。它包含數百萬條目(並且爲了使用而被正確索引)。

一個計劃線程每天運行一次刪除舊條目。此線程可能需要大量時間進行刪除,因爲由於不同的原因,要刪除的行數可能非常大(幾百萬行)。
在我的特定系統上刪除250萬行需要大約3分鐘。

的插入線(和讀取線程)得到一個超時錯誤,告訴我如何防止MySQL InnoDB通過JDBC爲刪除語句設置鎖定

Lock wait timeout exceeded; try restarting transaction 

1)好了,有一件事是,我怎麼能簡單地從我的Java代碼的狀態?我寧願自己處理這種情況,而不是等待。但更重要的是,如何防止這種情況?

2)我能用

conn.setIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED) 

爲讀線程,因此無論他們將獲得他們的信息,如果它是目前最準確的(這是絕對OK這個用例)?

3.)我能做些什麼來插入線程以防止阻塞?他們純粹插入數據到表中(主鍵是元組userid,servertimemillis)。

4.)我是否應該更改我的刪除線程 - 它純粹刪除元組userid的數據,大於specialtimestamp。

編輯:
當讀MySQL documentation here,我不知道如果我不能簡單地定義與

conn.setIsolationLevel(Connection.TRANSACTION_READ_COMMITTED) 

插入和刪除行的連接,實現我需要什麼。它表示UPDATE和DELETE語句使用唯一索引和唯一搜索模式只會鎖定匹配索引條目,但不會鎖定之前的差距,因此行仍可以插入到該差距中。因爲我不能簡單地在生產環境中嘗試它,所以在這方面獲得您的經驗將是非常好的 - 並且在測試環境中模擬它是一項巨大的努力。

回答

1

您可以嘗試用多個更短的DELETE ... LIMIT n替換您的一個巨大的DELETE,n在測試後確定(不會太小而不會導致許多查詢,並且不會太大而導致長鎖)。由於鎖會持續幾毫秒(或秒,取決於您的n),您可以讓刪除線程連續運行(假設它可以保持;再次調整n以便能夠保持)。 另外,table partitioning可以提供幫助。

+0

是的,那會比現在做得更好,我可以確定我不會鎖定其他線程太長。我將這一點考慮在內以作爲快速的解決方法,但正如您已經注意到的那樣,如果在下一個回合之前刪除的行數太大而無法在'x * n'時間段內刪除,那麼它可能會變得棘手開始...我的想法與'conn.setIsolationLevel(Connection.TRANSACTION_READ_COMMITTED)''怎麼樣? – Schlangi

+0

我試過在備份數據庫上,它的工作速度比單個刪除語句快得多。但它具有與鎖定相同的固有問題,即使這是因爲短時間的原因。 – Schlangi

+0

我將您的解決方案標記爲已接受,但我仍然在考慮對隔離級別的更改... – Schlangi

1

嘗試在您的刪除線程中首先加載要刪除的記錄的ID,然後一次刪除一個,每次刪除後提交。

如果您每天運行一次執行大量刪除操作的線程,並且需要3分鐘時間,則可以將其拆分爲較小的事務,這些事務刪除少量記錄,並且仍然可以快速完成。

更好的解決方案:

首先。您嘗試的任何解決方案必須在生產中部署之前進行測試。尤其是一些隨機的人在某個隨機網站上提出的解決方案。

現在,這裏的解決方案,我建議(作出有關你的表結構和索引一些假設,因爲你沒有指定它們):

  1. 改變你的表。不建議在InnoDB中使用主鍵,特別是在大表中(因爲主鍵自動包含在其他索引中)。更多原因,請參閱this question的答案。你應該添加一些唯一的RecordID列作爲主鍵(我推薦一個很長的標識符,或MySQL中的BIGINT)。

  2. 選擇要刪除的行 - 執行「SELECT RecordID FROM YourTable其中ServerTimeMillis <?」。

  3. 提交(以釋放ServerTimeMillis指數,我假設你有鎖,快)

  4. 對於每一個的recordId,執行 「DELETE FROM YourTable WHERE的recordId =?」

  5. 在每條記錄之後或每條X記錄之後提交(我不確定這是否會產生很大的差異)。也許在DELETE命令末尾即使是一個Commit也是足夠的,因爲使用我建議的新邏輯,只有被刪除的行應該被鎖定。

至於改變隔離級別。我不認爲你必須這樣做。我不能建議你是否可以做到這一點,因爲我不知道你的服務器的邏輯,以及它如何受到這種改變的影響。

+0

我不相信這是一個好主意。假設要刪除250萬行,如果每條語句僅持續0.0015秒,則需要大約一個小時。另一方面,鎖問題將被解決... – Schlangi

+0

@Schlangi查看我的更新回答 – Eran

+0

+1的詳細解釋,我會給另一個+1'首先。您嘗試的任何解決方案必須在生產中部署之前進行測試。特別是一些隨機的人在某個隨機網站上提出的解決方案。我不想讓你覺得我不會或不想測試...;) – Schlangi