我编写了这个函数来使用 Yii 框架命令行生成一个 CSV 文件现在的问题是我有超过 300,000 行数据要写入 CSV 文件。所以我所做的是,我为每个CSV文件将数据分成10,000个。
public function Targets2($offset,$limit,$batch){
if($offset == ''){
echo 'provied an offset!';
exit;
}
if($limit == ''){
echo 'provide a limit';
exit;
}
if($batch == ''){
echo 'you wil overwrite the 1st batch!';
exit;
}
$dataProvider=new CActiveDataProvider('users',
array(
'criteria' => array(
'order' => 'userid ASC',
'offset'=>$offset,
'limit' => $limit,
),
'pagination' => false
)
);
$datas = $dataProvider->getData();
$userdatas = array();
foreach($datas as $data){
$h = '"D"';
$ssn = '""';
$email = '';
$mobile_no = '';
$specialtargetname = '"special target"';
if(!is_null($data->USEREMAILADR) && !empty($data->USEREMAILADR)){
$email = '"'.$data->USEREMAILADR.'"';
} else {
$email = '""';
}
if(!is_null($data->USERCT) && !empty($data->USERCT)){
$mobile_no = '"'.$data->USERCT.'"';
} else {
$mobile_no = '""';
}
$userdatas[] = array('"'.$data->USERID.'"',$h,'""',$email,$mobile_no,$specialtargetname);
}
$headers = array(
'"USERID"',
'"H"',
'"SSN"',
'"EMAIL"',
'"MOBILE_NO"',
'"SPECIAL_TARGET_NAME"'
);
$date = date('Ymd',strtotime('today'));
$totaldata = count($userdatas);
$file = 'C:'xampp'htdocs'yii'branch'protected'data'Target_'.$date.'_'.$batch.'.csv';
$fp = fopen($file, 'w+');
fputcsv($fp,$headers,','," ");
if($totaldata > 0){
foreach($userdatas as $line){
fputcsv($fp,$line,','," ");
}
$end = array('"T"');
$fp2 = fopen($file,'a+');
fputcsv($fp2,$end,','," ");
echo "offset = $offset with limit $limit contacts file generated batch " . $batch ."'n";
fclose($fp);
fclose($fp2);
$offset = $limit;
$limit += 10000;
$batch += 1;
$this->Targets2($offset,$limit,$batch);
}
现在的问题是,在脚本写入第二批CSV文件之前,就会发生错误
Fatal error: Allowed memory size of 1744830464 bytes exhausted (tried to allocat
e 48 bytes) in C:'xampp'htdocs'yii1.1.10'framework'db'CDbCommand.php on line 506
即使我将memory_limit设置为 1664M,例如
ini_set('memory_limit','1664M');
我仍然收到致命的内存泄漏错误。
如果我将其设置为 "-1"
它会使服务器崩溃,我不想在生产中推送该代码。太可怕了。
如何解决或优化?
在
处理大量数据时,最好避免使用 CActiveRecord 实例,每个实例都会使用附加内存,使用纯数组会有所帮助。 此外,您还需要按如下方式查询块中的数据:
class ImportCommand extends CConsoleCommand
{
public function run($args)
{
$db = Yii::app()->db;
$limit = 1000;
$totalRows = $db->createCommand()
->from("users")
->select("count(*)")->queryScalar();
$n = ceil($totalRows / $limit);
$k = 0;
// $fp = fopen(...)
for($i = 0; $i < $n ; $i++)
{
$offset = $i*$limit;
$list = $db->createCommand()->from("users")
->offset($offset)
->limit($limit)->queryAll();
foreach($list as $user)
{
//process $user here
}
}
// fclose($fp)
}
}
此外,如果在查询生成器上使用 select 方法仅指定所需的字段,则可以节省更多内存。