2010-11-12 38 views
9

一位同事告訴我,執行SQL語句總是將數據放入數據庫服務器的RAM /交換中。因此選擇較大的結果集是不現實的。執行語句是否總是在內存中存儲結果集?

我認爲這種代碼

my $sth = $dbh->prepare('SELECT million_rows FROM table'); 
while (my @data = $sth->fetchrow) { 
    # process the row 
} 

由行中檢索結果集行,沒有它被加載到RAM中。 但我在DBI或MySQL文檔中找不到任何對此的引用。結果集是如何真正創建和檢索的?它對簡單的選擇和連接工作是否一樣?

+0

問題的目的,爲什麼你需要獲取數百萬行記錄並迭代獲取所有? 'mysqldump'應該更合適 – ajreal 2010-11-12 19:40:28

+0

@ajreal:我需要按插入順序處理所有行並生成一些報告。 – planetp 2010-11-15 10:49:31

+0

好的,這樣做是否合理?使用mysql函數生成視圖,臨時表不夠用於報告?或者甚至考慮將BIG結果轉儲到文件中,然後打開文件進行處理 – ajreal 2010-11-15 10:55:21

回答

6

你的同事是對的。

默認情況下,perl模塊DBD :: mysql使用mysql_store_result,它確實在所有SELECT數據中讀取並將其緩存在RAM中。除非您更改該默認值,否則當您在DBI中逐行讀取時,它只是將它們從內存緩衝區中讀出。

這通常是你想要的,除非你有非常大的結果集。否則,直到你從mysqld獲得最後一個數據爲止,它必須保持這個數據就緒,我的理解是它會在寫入相同行(塊?表?)時導致塊。

請記住,現代機器有很多RAM。一百萬行的結果集通常不是什麼大問題。即使每個行在1 KB時都很大,那只有1 GB RAM加上開銷。

如果您要處理數百萬行BLOB,也許您需要mysql_use_result - 或者您希望以具有LIMIT x,y的漸進式用途的塊來選擇這些行。

有關詳細信息,請參閱perldoc DBD::mysql中的mysql_use_result和mysql_store_result。

+0

+1,但不知道DBD :: mysql會這樣做。然而,除非你有耗盡內存的危險,否則你不應該關心的評論是BAD建議 - 作爲一般規則,你只應得到你需要的數據,如果你不需要數百萬行(你很少做),你不應該把他們全部。這種方法會使可擴展性無法修復(如果庫在應用程序級而不是在會話級進行緩存,情況會好一些,但仍然不好 - 如果此緩存經常失效,則您需要在需要的位置重複獲取1GB數據少得多) – Unreason 2010-11-14 22:19:55

1

我對此並不十分熟悉,但在我看來,像DBD :: mysql可以根據需要或根據需要,根據mysql_use_result屬性獲取所有內容。請參閱DBD :: mysql和MySQL文檔。

5

這不是真的(如果我們談論的是數據庫服務器本身,而不是客戶層)。

MySQL可以緩衝整個結果集,但這不一定完成,如果完成,不一定在RAM

的結果集,如果使用的是直列次(SELECT FROM (SELECT …))緩衝,查詢需要排序(其被示出爲using filesort)或計劃需要創建的臨時表(其被示爲using temporary在查詢計劃) 。

即使using temporary,MySQL只在內存大小未超過tmp_table中設置的限制時纔將內存保留在內存中。當表增長超過此限制時,它將從memory轉換爲MyISAM並存儲在磁盤上。

但是,您可以明確指示MySQL通過將SQL_BUFFER_RESULT指令附加到最外層的SELECT來緩衝結果集。

有關更多詳細信息,請參閱docs

3

不,這不是它的工作原理。

數據庫將不保存RAM /交換中的行。

但是,它會嘗試,並在這裏嘗試努力,儘可能緩存(索引,結果等)。你的mysql配置爲不同類型的緩存提供了可用內存緩衝區的值(對於不同類型的存儲引擎) - 你不應該允許這個緩存交換。

測試它
底線 - 它應該是很容易只測試此使用的客戶端(我不知道Perl的DBI,它可能會,但我懷疑這一點,可以做一些強制MySQL加載一切準備)。無論如何...測試它:

如果你實際上發出一個準備SELECT SQL_NO_CACHE million_rows FROM table,然後從數百萬只提取幾行。 然後,您應該將性能與SELECT SQL_NO_CACHE only_fetched_rows FROM table進行比較,然後查看票價。 如果表現可比(而且快),那麼我相信你可以打電話給你的同事虛張聲勢。

另外,如果你啓用實際發佈到mysql的語句的日誌,並給我們一個腳本的記錄,那麼我們(非perl的人)可以給mysql更多的確定性答案。

相關問題