2016-04-07 37 views
0

我使用gpars並行處理250M行的MySQL數據庫表。我創建了8個gpars線程,8個獨立的數據庫連接,並以這樣一種方式劃分數據,即每個線程獨立運行在不同的行數範圍內......這是一種便宜的MapReduce概念。在覈心,邏輯是這樣的:groovy應用與gpars在很多迭代後變慢

withExistingPool(pool) 
    { 
    connection_array.collectParallel()   
    { 
     // Figure out which connection this thread can use. 
     // We use the index into the array to figure out 
     // which thread we are, and this tells us where to 
     // read data. 

     int i 
     for (i = 0; i < connection_array.size(); i++) 
      if (it == connection_array[i]) 
      break 

     // Each thread runs the same query, with LIMIT controlling 
     // the position of rows it will read...if we have 8 threads 
     // reading 40000 rows per call to this routine, each thread 
     // reads 5000 rows (thread-0 reads rows 0-4999, thread-1 reads 
     // 5000-9999 and so forth). 

     def startrow = lastrow + (i * MAX_ROWS) 
     def rows = it.rows("SELECT * ... LIMIT ($startrow, $MAX_ROWS)") 

     // Add our rows to the result set we will return to the caller 
     // (needs to be serialized since many threads can be here) 

     lock.lock() 
     if (!result) 
      result = rows 
     else 
      result += rows 
     lock.unlock() 
    } 
} 

該代碼最初工作得很好,每秒啓動時超過10,000行。但是在幾百萬行之後,它開始減速。當我們有2500萬行,而不是每秒10000行時,我們每秒只能獲得1,000行。如果我們終止應用程序並從我們停止的地方重新啓動應用程序,它會再次回到每秒10K行一段時間,但隨着處理的繼續,它會一直減慢。

有大量的處理能力可用 - 這是一個8路系統和數據庫是在網絡上,所以有等待時間公平一點不管。處理器運行時一般不會超過25-30%的繁忙時間。也似乎沒有任何內存泄漏 - 我們監視內存統計信息,並且在處理進行之後看不到任何更改。 MySQL服務器似乎沒有被強調(它最初運行的時候大約佔30%,隨着應用程序的減速而下降)。

是否有任何技巧可以幫助這類事物在大量迭代中更一致地運行?

+0

這可能是因爲你不斷調整結果列表的大小。你有沒有嘗試指定一個初始大小的結果?你不會顯示它的初始化方式/你在哪裏初始化 –

+0

你也可以使用'(0 ..

+0

@ tim - 感謝您的建議......您的第一條評論是一個很好的評論 - 因爲我們知道有多少行被提取,所以我們可以預先分配結果並將其作爲參數傳遞,而不是每次動態構建它。這幫助了近5%的表現。第二個建議實際上比我們原來的方法慢了一點 - 我想這不需要很長時間就可以搜索一個8項數組。不幸的是,最初的問題仍然存在......例程越來越慢越多的記錄它處理。 –

回答

0

好吧,我們認爲發現了問題 - 這似乎是它與開在不同的線程比它用在JDBC連接做。通過最初打開它將要使用的線程上的連接,然後確保只有該線程訪問該連接,性能問題就消失了。

我們還修改了邏輯有點使用基於遊標的方法,而不是用LIMIT多個查詢。有報道說,具有高start_row的LIMIT可能會很慢,但我們沒有看到有什麼大的區別,只是通過進行此更改(遊標速度更快,但在處理行時性能仍然下降)。

不過,這和一些變化tim_yates之間的建議,我們正在運行速度比以前快了良好的30% - 現在它的持續快速不管我們有多少行處理。

+0

不要忘記我上面的評論中的收集/每件事 –

0

LIMITOFFSET是效率不高,因爲大多數人都會喜歡。

在做LIMIT 1000,20,1000行將被讀取,但跳過,那麼20行會被讀取並交付使用。也就是說,隨着OFFSET的增長,查詢變慢。

「解決」這個技術是「記住你離開的地方」。主鍵AUTO_INCREMENT特別容易,但可以用任何PRIMARY KEYUNIQUE鍵完成。

這是discussed further in my "Pagination" blog。它針對網頁上的「下一步」按鈕,因此可以忽略一些討論。