2014-12-04 66 views
1

我在centos 6上使用Yii 1.1.14和php 5.3,我使用CDbCommand從一個非常大的表中獲取數據,結果集是大約10萬列的90,000條記錄我將它導出爲csv文件,文件大小約爲15MB, 腳本始終崩潰而沒有任何錯誤消息,只有經過一些研究後,我發現我需要在php.ini中提高memory_limit以便能夠成功執行腳本。 唯一的問題是,爲了成功執行,我必須將內存限制提高到512MB(!),這是很多!如果10個用戶將執行相同的腳本我的服務器將不會很好地響應...Yii大型SQL查詢消耗大量內存

我想知道是否有人可能知道減少與Yii的SQL查詢的內存消耗的方式? 我知道我可以使用限制和偏移量將查詢拆分爲多個查詢,但15MB查詢消耗512MB似乎並不合邏輯。

下面是代碼:

set_time_limit(0); 
$connection = new CDbConnection($dsn,$username,$password); 
$command = $connection->createCommand('SELECT * FROM TEST_DATA'); 
$result = $command->queryAll(); //this is where the script crashes 
print_r($result); 

任何想法,將不勝感激!

感謝,

+0

你確定問題的心不是在數據庫?如果它是一個非常大的查詢,你可能會計時PHP而不是耗盡內存。我假設你在MySQL上。也許嘗試一些索引來加速它,否則你會被限制和抵消或遷移到NoSQL解決方案 – 2014-12-04 13:40:40

+0

因此,你認爲如果寫入文件時某些內容需要15MB,則在轉換該文件時它必須分配相同數量的內存到保存信息的語言的數據結構?但要回答你的問題,你已經(正確)猜到了什麼 - 使用LIMIT和OFFSET。不要一次加載所有內容。計算你有多少行,並在移動到下一個5k行之前對5k行進行操作 - 直到完成所有90k行。 – 2014-12-04 13:47:19

+0

嗨,謝謝你的回覆! @mike miller,不應該有一個時間問題,因爲腳本失敗很快~5秒,並且我已經將時間限制設置爲0 .. – AssafW 2014-12-04 15:38:03

回答

4

而不是使用readAll的,將返回在單個陣列(實存儲問題是在這裏),你只需要使用一個foreach循環中的所有行(看看CDbDataReader),例如:

$command = $connection->createCommand('SELECT * FROM TEST_DATA'); 
$rows = $command->query(); 
foreach ($rows as $row) 
{ 

} 

編輯:使用LIMIT

$count = Yii::app()->db->createCommand('SELECT COUNT(*) FROM TEST_DATA')->queryScalar(); 
$maxRows = 1000: 
$maxPages = ceil($count/maxRows); 
for ($i=0;$i<$maxPages;$i++) 
{ 
    $rows = $connection->createCommand("SELECT * FROM TEST_DATA LIMIT $i,$maxRows")->query(); 
    foreach ($rows as $row) 
    { 
    } 
} 
+0

嗨,這種方法非常好,使用你的例子我能夠創建一個大約有110,000個記錄的16MB文件,所以這是一個大約20%的改進!但腳本仍然在$ rows = $ command-> query();失敗。當試圖獲得更多的記錄...任何想法? – AssafW 2014-12-04 15:43:18

+0

您應該使用LIMIT – soju 2014-12-04 16:14:57

+0

答案更新。 – soju 2014-12-04 16:22:15