2014-10-17 35 views
0

我在mac pro,64GB內存,6個內核上運行mysql服務器。我的模式中的Table1有三億三千萬行。表2有65,000行。 (我還有其他幾張表格,總共約有15億行,但它們並沒有用於我嘗試的操作中,所以我認爲它們並不相關)。Mysql在更新時超出系統內存選擇

我試圖做我會想到的是一個相對簡單的更新語句(見下文)將表2中的一些數據帶入Table1。但是,我在使用我的系統內存時遇到了一段可怕的時間,迫使我換掉了內存,並最終凍結了整個系統,導致mysql無響應,我需要重新啓動計算機。我的更新聲明如下:

UPDATE Table1, Table2 
SET 
    Table1.Column1 = Table2.Column1, 
    Table1.Column2 = Table2.Column2, 
    Table1.Column3 = Table2.Column3, 
    Table1.Column4 = Table2.Column4 
WHERE 
    (Table1.Column5 = Table2.Column5) AND 
    (Table1.Column6 = Table2.Column6) AND 
    (Table1.Column7 = Table2.Column7) AND 
    (Table1.id between 0 AND 5000000); 

最終,我想爲Table1中的所有3.3億行執行此更新。我決定把它分解成500萬線批次每個雖然因爲

  • (一)我是越來越有超過鎖大小和問題
  • (B)我想這可能與我通過吹的問題幫助內存。

以下是有關的情況更多一些相關的細節:

  • 我已經創建了兩個表1和表2指標超過Column5,Column6,Column7的組合(其值我匹配的列) 。
  • 表1有50列,總共大約60 GB。
  • 表2有8列,總共3.5 MB。
  • 我知道有些人可能會在這種情況下推薦外鍵,而不是使用table2中的信息更新table1,但(a)我有足夠的磁盤空間,並且不會真正在意使用它來達到最高效率(b)這些表中的任何值都不會隨着時間而改變,(c)我最擔心的是在table1上運行的查詢的速度,如果從table2到table1的信息需要這麼長時間,我當然不希望需要爲我在table1上運行的每個查詢重複該過程。
  • 針對超過最大鎖表大小的問題,我嘗試了增加innodb_buffer_pool_size。我已經嘗試了一些值。即使在低至8 GB(即我的電腦內存的1/8,並且在執行此操作時幾乎沒有任何其他內容)的情況下,我仍然遇到mysqld進程的這個問題,基本上所有的ram在系統上可用,然後開始從操作系統中提取內存分配(即,我的kernel_task開始顯示爲使用30GB內存,而通常使用大約2GB)。
  • 最大鎖的問題似乎已經基本解決;我不再犯這個錯誤,雖然也許那是因爲現在我在我能夠到達那裏之前衝破我的記憶和崩潰。
  • 我已經嘗試過較小的批量(100萬行,100,000行)。這些似乎可能比500萬行批次更好一些,但它們通常仍然存在相同的問題,可能只是開發速度稍慢。而且,性能看起來很糟糕 - 例如,按照10萬批量處理的速度,執行此更新需要大約7天的時間。
  • 這兩個表都使用InnoDB
  • 我一般設置SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;雖然我不知道它是否真的有幫助(我是唯一一個以任何方式訪問這個數據庫的用戶,所以我不在乎鎖定,如果可以的話我會完全廢除)
  • 我注意到批次運行所花費的時間變化很大。例如,在100萬行批次中,我會觀察45秒到20分鐘之間的任何時間。
  • 當我嘗試運行一些剛剛找到匹配行的東西,然後只將這兩個列值放入新表格時,我獲得了更加一致的時間(每百萬行約2.5分鐘)。因此,似乎我的問題可能以某種方式來源於事實,也許我更新表中正在進行匹配的值,即使我正在更新的列與我所匹配的列不同。
  • 我在匹配和更新的列中只包含INT和CHAR類型,其中最多不超過7個字符。
  • 我跑了一個CHECK TABLE診斷,它回來了。
  • 總的來說,我非常困惑,爲什麼這會如此困難。一般來說,我對mysql和數據庫是新手。由於Table2非常小,我可以用Python查找字典來完成相同的任務,我相信可以更快。我會認爲,儘管數據庫能夠更好地處理這個問題,因爲處理和更新大數據集是他們的設計目標。
  • 我使用Mysql工作臺對查詢運行了一些診斷,並確認沒有執行全表掃描。
  • 雖然這裏看起來確實有些問題。如果系統具有64 GB的ram,並且這大於兩個表的總大小(儘管統計索引大小對於兩個表而言是多於64GB),並且如果該操作僅應用於在每次3.3億行中有500萬行,這意味着它應該吹出公羊。

因此,我想知道:

  1. 就是我如何寫這update語句莫名其妙可怕的壞,效率低下,使得它可以解釋可怕的性能和問題的語法?
  2. 除了我應該配置的innodb_buffer_pool_size之外是否還有一些參數,要麼在MySQL使用的內存上放置一個更牢固的上限,要麼讓它更有效地使用資源?
  3. 是否還有其他類型的診斷,我應該運行以嘗試檢測我的表格,模式等問題?
  4. 什麼是期望這樣更新的「合理」時間量?

回答

0

因此,有幾個人知道所述事項的協商後,這裏是我想出瞭解決方案:

  1. 我把我的innodb_buffer_pool_size到4GB,我的整個系統,即1/16記憶。這似乎足以可靠地阻止MySQL通過我的64GB內存。

  2. 我簡化了我的索引,以便它們只包含我所需要的列,並確保我使用的所有索引都足夠小以適合內存(有足夠的空間可供MySQL的其他用途使用)以及)。

  3. 我學會了接受MySQL似乎並不是爲特別大的數據集(或者至少不是在一臺機器上,即使是像我這樣的相對較大的機器)而構建的。因此,我承認手動分批分批工作往往是必要的,因爲MySQL的機制顯然不具備如何獨立完成工作的正確決策所需要的東西,以便對RAM等系統資源非常認真。

  4. 有時候,當按照這個或者一般來說,在我的中等大小的數據集上進行工作時,我會使用MySQL來執行更新和連接。其他時候,我只是將數據分解成塊,然後在另一個程序中執行加入或其他此類操作,例如R(通常使用類似data.table的包,以相對高效地處理較大的數據)。

  5. 我還被告知,或者,我可以在Hadoop集羣上使用像Pig of Hive,這應該能夠更好地處理這種大小的數據。