将大型Doctrine 2查询结果流式传输到

时间:2016-04-26 13:39:50

标签: php mysql performance doctrine-orm doctrine

在我的项目中,我有一个API调用,可能会返回数万条记录。

数据应该在一个块中返回。 API设计不允许分页。

使用Doctrine 2 DQL从MySQL查询源数据,每个记录包含多个链接对象。目前查询结果大约是25&000; 000条记录。我已经优化了SQL查询。它在几毫秒内运行,因此无法在此进行优化。

主要问题是水合作用。我尝试过不同类型的水合作用,但这些数据仍需要很长时间。它也使用了太多的内存。

我的想法是在数据被水合后立即流式传输数据,然后在数据流传输后立即删除数据。它不会减少完成请求的时间,但会减少内存使用量并减少响应开始前的时间。

在每个结果行被水合后,Doctrine 2中是否有办法执行某些操作?

即。我提出了很大的要求。我做$qb->getQuery()->getResult()和Doctrine而不是保湿所有数据并在每个记录被水合后返回结果将数据发送到例如STDOUT并在数据流传输后立即丢弃对象。

PS:问题不是关于如何将此类查询的输出流式传输到HTTP。我能解决这个问题。问题是如何让Doctrine 2做我想做的事。

1 个答案:

答案 0 :(得分:5)

我的解决方案(包括完整性的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"');