在我的项目中,我有一个API调用,可能应该返回数万条记录。
数据应以一个块返回。API 设计不允许分页。
源数据使用原则 2 DQL 从 MySQL 查询,并且每条记录包含多个链接对象。目前,查询结果约为 25'000 条记录。我已经优化了 SQL 查询。它在几毫秒内运行,因此无法在此处进行优化。
现在的主要问题是水合作用。我已经尝试了不同类型的水合,但仍然需要很长时间来处理这些数据量。它还使用太多内存。
我的想法是在数据被冻结后立即流式传输数据,然后在流式传输后立即删除数据。它不会减少完成请求的时间,但会减少内存使用量,并减少响应开始之前的时间。
原则 2 中是否有办法在每个结果行水合后执行一些操作?
即我做大要求。我做$qb->getQuery()->getResult()
和学说,而不是水化所有数据并在每条记录被水化后返回结果,将数据发送到例如 STDOUT 并在数据流式传输后立即删除对象。
PS:问题不是关于如何将此类查询的输出流式传输到HTTP。我可以处理。问题是关于我如何让教义2做我想做的事。
我的解决方案(包括用于完整性的 CSV 流):
function getExportableHead()
{
// returns array of fields for headings
}
function getExportableRow($row)
{
// returns array of values for a row
}
$qb = $this->em->getRepository(Item::class)->createSomeQueryBuilder();
$response = new StreamedResponse(function () use ($qb) {
$data = $qb->getQuery()->iterate();
$handle = fopen('php://output', 'w+');
fputcsv($handle, getExportableHead(), ';');
while (($object = $data->next()) !== false) {
$row = getExportableRow($object[0]);
fputcsv($handle, $row, ';');
$this->em->detach($object[0]);
}
fclose($handle);
});
$response->headers->set('Content-Type', 'text/csv; charset=utf-8');
$response->headers->set('Content-Disposition', 'attachment; filename="out.csv"');