2014-04-01 61 views
11

我得到了一個約數據庫的mysql數據庫。 1 TB的數據。表fuelinjection_stroke有apprx。 1.000.000.000行。 DBID是每個插入自動遞增1的主鍵。mysql - 從InnoDB中刪除行非常慢

我想用一個非常簡單的語句刪除第1000000行:我的專用8core至強服務器上

Delete from fuelinjection_stroke where DBID < 1000000; 

此查詢將士很長(> 24小時)(32 GB內存,SAS存儲)。

任何想法的過程是否可以加快?

+0

1 Bn行相當多。除了pkey之外,桌面上還有任何索引嗎?刪除行時,索引必須更新,這可能需要時間。 我不確定它是否會在這種情況下工作,但是您可以嘗試在事務中執行刪除並查看它是否工作得更好? – troelskn

+0

對於OP,您可以更新我們對此的結果,我真的很感興趣。 :) –

+2

刪除非常緩慢。在10.000s的部分中刪除的方法可行 - 但這並沒有加速整個過程。我結束了以下工作:使用mysqldump將表格轉儲到一個文件中。然後,我使用sed -i'1,1000000d'file.sql從轉儲文件中刪除行。我截斷了表格並重新載入了轉儲文件......結果是最快的方法... – user1938509

回答

15

我相信你的表變得鎖定了。我遇到同樣的問題,並發現可以非常快地刪除10k記錄。所以你可能想編寫簡單的腳本/程序,它將通過塊刪除記錄。

DELETE FROM fuelinjection_stroke WHERE DBID < 1000000 LIMIT 10000; 

而且一直保持到它會刪除所有執行它

+0

正在進行的調查指向了兩個方向: 1)由於表格非常大,所以需要很長時間。 2)mysql實例是主從複製的主設備。儘管表中沒有任何索引或外鍵,但兩臺服務器之間的二進制日誌複製似乎會減慢進程速度。 這裏建議的解決方案是有效的,因爲一個聲明不會結束。 – user1938509

+1

仍不確定此解決方案的工作原理。 – RyanShao

-6

我不知道確切的答案。但寫另一種方式刪除這些行,請試試這個。

delete from fuelinjection_stroke where DBID in 
(
    select top 1000000 DBID from fuelinjection_stroke 
    order by DBID asc 
) 
3

你有什麼指標?

我認爲你的問題是,刪除是在每次迭代重建索引。

我會刪除索引,如果有的話,做刪除,然後重新添加索引。它會更快,(我認爲)。

+2

也禁用對此表的外鍵引用,如果有的話。 – RandomSeed

0

您的數據庫可能正在檢查需要在外鍵(級聯,刪除)中修改的記錄。

但I-Conica答案是一個很好的觀點(+1)。刪除單個記錄並在完成100000次時更新大量索引的過程效率不高。只需刪除索引,刪除所有記錄並重新創建。

當然,檢查數據庫中是否有任何類型的鎖。一個用戶或應用程序可以鎖定一個記錄或表,並且您的查詢將等待,直到用戶釋放資源或達到超時。檢查數據庫是否正在進行實際工作或等待的一種方法是查詢來自將--innodb_lock_wait_timeout參數設置爲幾秒的連接的查詢。如果它至少失敗,你就知道查詢是可以的,並且你需要找到並釋放該鎖。鎖的例子是Select * from XXX For update和uncommited transactions。

+0

我不太清楚,如果我明白這個答案。我的表沒有任何索引。只有一個主鍵DBID(在插入期間自動增量)。 我的理解是,如果沒有至少一個唯一索引,Innodb不能工作,如果沒有明確指定,它將會隱式創建:「如果表沒有PRIMARY KEY或合適的UNIQUE索引,InnoDB會在內部生成一個隱藏的聚集索引列包含行ID值,這些行按照InnoDB分配給此表中行的ID進行排序。「 – user1938509

+0

如果您只有一個主鍵索引,我認爲問題不是索引。請檢查是否沒有外鍵關係。 (例如,如果您每次刪除一條記錄時都有fuelinjection_stroke_history,則必須檢查此輔助表中的孤兒,即1000。000查詢) 查詢結束了嗎?如果不是,我會認爲它是一個鎖。 – borjab

+1

數據庫ist複製(主/從) - 這會減慢進程(binlogs)。該表沒有任何外鍵等... – user1938509

4

你的空間被剝奪?停機時間不可能嗎?

如果不是,則可以將新列的INT列長度設置爲1,默認爲1表示「活動」(或任何術語),0表示「非活動」。實際上,如果需要,你可以使用0到9作爲10個不同的狀態。

添加這個新列需要花費很長時間,但一旦結束,只要您從主元件開始執行更新(就像使用DELETE操作一樣),您的UPDATE應該快如閃電,而且不會索引這個新元件柱。

InnoDB在如此龐大的表上刪除這麼長時間的原因是因爲集羣索引。它基於您的PRIMARY(或第一個UNIQUE找到...或者無論它發現PRIMARY還是UNIQUE都沒有),所以當你拔出一行時,它現在會在磁盤上物理地重新整理你的ENTIRE表,以便進行速度和碎片整理。所以這不是DELETE這麼長時間。這是刪除行後的物理重新排序。

當您使用默認值創建一個新的INT列時,空間將被填充,因此當您更新它時,不需要對您的巨大表格進行物理重新排序。

我不確定你的模式究竟是什麼,但使用列的狀態比DELETEing快得多;但是,它會佔用更多的空間。

嘗試設置值:

innodb_flush_log_at_trx_commit=2 
innodb_flush_method=O_DIRECT (for non-windows machine) 
innodb_buffer_pool_size=25GB (currently it is close to 21GB) 
innodb_doublewrite=0 
innodb_support_xa=0 
innodb_thread_concurrency=0...1000 (try different values, beginning with 200) 

參考文獻:

MySQL docs for description of different variables.

MySQL Server Setting Tuning

MySQL Performance Optimization basics

http://bugs.mysql.com/bug.php?id=28382

+0

我試圖釋放數據,因爲我的sas san接近100% - 它只有4TB。 – user1938509

+0

基於此,我不明白爲什麼刪除速度越快,刪除的行越少。當你刪除_N_行(在一個'DELETE'中)時,它不會重新組織表_N_次嗎?因爲我剛剛建議添加一個'MarkedForDeletion'列,但是更進一步,並添加了一個異步操作,它將逐步將它們在物理上刪除(如接受的答案所暗示的,以及我在其他地方所聽到的) ...而且效果很好! –

0

我有同樣的問題,我的表有幾個我不想丟棄和重新創建的索引。所以我做了以下工作:

create table keepers 
select * from origTable where {clause to retrieve rows to preserve}; 
truncate table origTable; 
insert into origTable null,keepers.col2,...keepers.col(last) from keepers; 
drop table keepers; 

大約220萬行在大約3分鐘內被處理。