2016-04-26 69 views
2

在我的项目中,我有一个API调用,可能会返回数以万计的记录。将大型学说2的查询结果输出到输出

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

使用Doctrine 2 DQL从MySQL查询源数据,并由每个记录的多个链接对象组成。目前查询结果大约是25000条记录。我已经优化了SQL查询。它在几毫秒内运行,因此无法在此优化。

现在的主要问题是水合作用。我尝试了不同类型的保湿剂,并且这些数据量仍然过长。它也使用太多的内存。

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

在教条2中有没有一种方法可以在每个结果行进行水合后执行一些操作?

I.e.我做了大的要求。我做$qb->getQuery()->getResult()和Doctrine而不是保湿所有的数据,并返回每个记录水合后的结果发送数据,例如标准输入和删除对象,只要数据流。

PS:问题不在于如何将此类查询的输出流式传输到HTTP。我可以处理。问题是关于如何让教条2做我想要的。

+0

这是一个很好的问题。我很惊讶没有人回答(可能太多的文字)。如果你最终做到了,那么对你的解决方案感兴趣。我想我们必须用'fetchOneRecord()'或类似的东西循环 –

回答

4

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