我使用Moodle 4.1
需要使用 php cli 运行脚本,该脚本将用近百万行数据填充 csv 文件。
<?php
define('CLI_SCRIPT', true);
require "config.php";
use core_reportbuilder\table\custom_report_table_view;
$table = custom_report_table_view::create(264);
$table->setup();
$table->download = 'excel';
$columns = (new table_dataformat_export_format($table, $table->download))->format_data($table->headers);
[$sql, $params] = $table->getPaginatedDataSQL();
$filePath = '/var/excelreport/tmp_264_' . date("d-m-Y_H:i:s") . '.csv';
try {
$file = fopen($filePath, 'w');
fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF));
echo "File '$filePath' successfully created.";
} catch (\Throwable $throwable) {
echo $throwable->getMessage();
echo "Failed to create '$filePath'.";
}
$limit = 10000;
$rowCount = $table->getRowsCount();
fputcsv($file, $columns,';');
for ($offset = 0; $offset < $rowCount; $offset += $limit) {
$chunk = $DB->get_records_sql($sql. " LIMIT $limit OFFSET $offset", $params); // here $DB is global variable which comes from config.php
foreach ($chunk as $row) {
$row = array_values($table->format_row($row));
fputcsv($file, $row,';');
}
echo "\n offset $offset memory: ". (memory_get_usage() / 1024)."KB\n" ;
unset($chunk);
gc_collect_cycles();
}
$table->close_recordset();
fclose($file);
我只需从 Moodle 的数据库中获取大小为 10000 行的数据块,并在每次迭代中使用 fputcsv 附加到文件中。每次迭代后,我都会回显内存使用量,该使用量随着脚本运行而增加。
我是否错过了一些需要释放的东西,或者 php 在长时间运行的任务中以某种方式增加了其内存占用?作为解决方案,我应该使用 exec 将每个块作为单独的进程执行吗?
让数据库完成工作
取决于数据库
对于MySql
https://dev.mysql.com/doc/refman/8.0/en/select-into.html
$exportsql = "{$sql} INTO OUTFILE '{$filePath}'";
对于 Postgresql
https://www.postgresql.org/docs/current/sql-copy.html
$exportsql = "COPY ({$sql}) TO '{$filePath}' WITH CSV HEADER";
然后执行SQL
$DB->execute($exportsql, $params);