2013-01-07 23 views
2

我有超過700萬行的這張表,而我的LOAD DATA LOCAL INFILE每次有50萬行數量的更多數據。前幾次是快速的,但是這除了正在越來越長,可能是由於索引開銷:如何提高大型InnoDB表上的LOAD DATA性能?

CREATE TABLE `orthograph_ests` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
    `digest` char(32) NOT NULL, 
    `taxid` int(10) unsigned NOT NULL, 
    `date` int(10) unsigned DEFAULT NULL, 
    `header` varchar(255) NOT NULL, 
    `sequence` mediumblob, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `digest` (`digest`), 
    KEY `taxid` (`taxid`), 
    KEY `header` (`header`) 
) ENGINE=InnoDB AUTO_INCREMENT=12134266 DEFAULT CHARSET=latin1 

我開發,將在預先存在的數據庫上運行的應用程序。我很可能無法控制服務器變量,除非我強制要求對其進行更改(我不希望這樣做),所以我很害怕像these這樣的建議的用處有限。

我讀過,最小化這個表上的鍵將有所幫助。但是,我需要這些密鑰以供稍後查詢。我猜如果我放棄並重新創建它們也需要很長時間,但我沒有測試過這個。我也讀過,特別是UNIQUE約束使插入緩慢。 digest列將採取SHA256摘要必須是唯一的,我不能確定沒有碰撞(很可能,我知道,但可能)。

分區幫助,建議here?我可以通過限制digest列上的密鑰長度來改進索引嗎?我應該更改爲MyISAM,它在transcactions期間支持DISABLE KEYS?我還有什麼可以提高LOAD DATA的性能?

編輯:

大插入後,此表僅用於SELECT S,沒有更多的寫入。這種大型加載大多是一次性完成的操作,但是在完成之前需要上傳大約1,000個數據集(每個0.5M行)。

我將使用摘要來查找行,這就是爲什麼我索引該列。如果發生碰撞,則不應上傳該行。

sequence BLOB在外部文件系統可能不是一個可行的選擇,因爲我不能輕易地強加給用戶的文件系統的變化。

+0

「非常不可能的,我知道,但有可能」這更可能是您的服務器隨機存儲器位翻轉。您不需要計劃SHA-256衝突。 – usr

+0

請澄清一些事情:該表格是作爲參考表格使用的,還是您將進行生產交易來改變它?你會定期加載一半的新數據嗎?或者這是加載一次完成的操作?你的摘要欄的目的是什麼 - 你會使用摘要來查找生產中的行嗎?如果您的摘要確實遇到了散列衝突,那麼您的恢復計劃是什麼?你有沒有考慮過把你的序列列(你的斑點)放在外部文件系統中? –

+0

@OllieJones:感謝您的評論。編輯了這個問題。 – mpe

回答

2

這確實是您正在加載的大量數據,您應該預計它需要花費數十個小時,尤其是在通用共享服務器硬件上。有很少的魔力(除非你在谷歌或其他什麼地方工作),這將使得這項工作不僅僅是一個巨大的痛苦。所以有勇氣。

這是一個參考表。這意味着你應該立即切換到MyISAM並留在這裏。您不需要InnoDB的事務完整性功能,但您需要MyISAM在加載過程中禁用索引並在之後重新啓用它。重新啓用索引需要很長時間,所以請爲此做好準備。

您應該考慮使用比SHA-256更短的散列。 SHA-1(160位)很好。相信與否,MD-5(128位)也可以提供服務。 MD-5已被破解,所以它不適合安全的內容認證。但它仍然是一個有用的散列。從您的角度來看,較短的散列是一個更好的散列。

如果您可以禁用索引MyISAM風格,那麼您的摘要密鑰是否是唯一的可能無關緊要。但是你可能會考慮讓它不是唯一的以節省時間。

很難在不瞭解數據和服務器硬件的情況下提出有關分區的建議。但考慮到這是一個參考數據庫,似乎只是咬幾個星期的子彈並加載它纔是明智之舉。

如果你有大量的服務器磁盤空間,可以考慮每個半megarow塊加載到它自己的表,然後將其插入大表。這可能被證明是一種很好的方法來處理你有可能在一天內重新加載整個事件的可能性。

在共享服務器硬件,它可能是有意義的使用更小的塊比一半megarow。

你可能會考慮一個單獨的ID /消化表。然後,您可以加載沒有摘要的數據並快速完成。然後,您可以自己寫一個存儲過程或客戶端,它們將分批創建幾千行的摘要,直到完成爲止。這僅適用於正在消化的東西在您的數據集中。

+0

非常感謝您的意見和寶貴建議! – mpe

1

基本上有兩個原因,數據加載很慢:在插入數據本身

  1. 寫性能。
  2. 讀取現有數據的性能,以加載現有數據,以便在添加新數據時修改現有頁面。

寫入性能問題都可以通過減少主要是耐用性和減少日誌加以解決。這就是您會發現的許多建議,例如以下設置:innodb_flush_log_at_trx_commit=0,innodb_doublewrite=0,innodb_support_xa=0。減少寫入數據的數量也可能有幫助,例如通過設置log-bin=0。不過,期望您的客戶在現有生產系統中更改這些耐用性相關設置也是不可接受的。更改它們更適合在專用系統上進行一次批量加載,而不是定期向現有系統添加數據。

批量加載INSERT(與許多行)或LOAD DATA INFILE尋求通過在單個事務中寫入更多的數據,從而降低了同步的所述事務日誌的數量,以減少寫入吞吐量要求。儘管如此,降低寫入吞吐量或提高寫入性能只會有所幫助。

在加載之前,通過PRIMARY KEY對數據進行排序通常也會很有幫助,以便在將數據插入索引結構時減少不必要的頁面拆分量。但是,如果存在多個輔助密鑰,則該用途的用途有限,因爲按PRIMARY KEY進行排序必然意味着數據不會被至少一個輔助密鑰排序。

讀取性能問題也許更有趣,並且經常與加載新數據到現有的表中的實際性能問題,尤其是在二次項存在。最好的辦法是將所有現有的數據放入內存(innodb_buffer_pool_size足夠大),以便在加載過程中不需要將數據分頁進入緩存或從緩存中分頁。鑑於你只談了幾百萬行,這可能是可行的。

+0

感謝您的意見。我不明白你關於讀取性能問題的觀點:你是指實際的I/O讀取性能?因爲我認爲我的性能問題與索引開銷有關。關於緩衝:這可能確實有幫助,但我正在使用'LOAD DATA',據我所知,它不使用緩衝池。 – mpe

+0

在InnoDB中,始終使用緩衝池。這是緩存數據的主要機制(如頁面,而不是行)。基本上,如果緩衝池不足以容納所有現有數據,則當寫入需要修改將在同一頁面上的數據(鍵值彼此靠近)時,該頁面必須首先加載到緩衝區中池。 – jeremycole

+0

感謝您的解釋!但是,由於我無法訪問服務器變量,因此恐怕您的建議在這種情況下使用有限。 – mpe