2016-05-26 55 views
0

我需要刪除舊的數據庫條目有效負載,同時保持相同條目的其他數據(id和其他屬性)。 有問題的表有message_id列(其中包含與其他信息連接的日期戳記),內容列(它是BLOB,它佔數據庫總大小的90%)以及其他一些我們沒有用到的列在這種情況下。如何從單列中清除大MySQL數據庫舊條目?

我第一次嘗試運行簡單的更新狀態:

UPDATE LOW_PRIORITY repository SET content="" WHERE SUBSTR(message_id, 6, 6)<201601 AND message_box = "IN"; 

我提取YYYYMM從每個條目MESSAGE_ID,如果它比選擇截止本月舊的 - 我更換內容有空字符串。

數據庫超過25GB的大小,並在我的表保存幾乎2KK條目,並在一個很不起眼的硬件上運行,而我的查詢運行一段時間後失敗,錯誤:

ERROR 2013 (HY000): Lost connection to MySQL server during query 

通常我儘量避免更改數據庫變量,但我知道,當你試着從一個大型轉儲文件還原數據庫這個錯誤還彈出,所以我就和更新的設置來處理100MB的數據包大小:

set global max_allowed_packet=104857600; 

重新運行我的UPDATE查詢導致一個新的錯誤:

ERROR 2013 (HY000): Lost connection to MySQL server during query 

正如我前面提到的 - 我的MySQL服務器運行在一個非常溫和的硬件,我不希望修改設置,可以使服務器超過可用的資源,因此,而不是增加所有可用超時數據庫變量,我決定用這樣的查詢運行我的較小的塊查詢:

UPDATE LOW_PRIORITY repository SET content="" WHERE message_id in (select message_id from(select message_id from repository where SUBSTR(message_id, 6, 6)<201603 AND message_box = "IN" limit 0, 1000)as temp); 

此查詢失敗,出現錯誤:

ERROR 1206 (HY000): The total number of locks exceeds the lock table size 

即使限制爲「限制1」的單行,也會出現同樣的查詢失敗!

不正確地使用分頁,還是有另一種更好的方法來做到這一點?

* DB正在運行一個虛擬Ubuntu服務器,雙核英特爾CPU,1GB內存和100GB硬盤。我完全沒有足夠的日常任務,我真的不想爲這個查詢增加規格。

回答

1

您試圖以複雜的方式(複雜的=更多的資源)欺騙mysql進行不想要的事情(使用limitin-語句中)。這是沒有錯的,但你可以只寫

UPDATE LOW_PRIORITY repository SET content="" 
WHERE content <> "" 
and SUBSTR(message_id, 6, 6) < 201603 AND message_box = "IN" 
limit 1000; 

這將更新仍然有它的內容第1000箇舊行。

+0

裏的不同位置有datestamp完美的解決方案! 我試圖分頁時,我並不需要。爲了限制受到影響的行數,我嘗試手動選擇範圍,並且在_UPDATE_中不可能進行子查詢。相反,您的解決方案是添加另一個條件來排除已更新的行,而不必關心查詢是否會再次觸發它們。 – Andris

0

我想你的#1問題在於你的WHERE條件將無法使用message_id字段的索引。

爲什麼不能簡單地做:

WHERE message_id < 20160100* ... 

假設這是整場,201512 **會少了201601 **反正所以就在你的結果沒有改變。但刪除子字符串函數將允許您在該字段上使用索引。

+0

不幸的是它是一個字符串,它有一些連接到它的字母數字值。此外,不同的_messagebox_值將在_message_id_ – Andris

相關問題