2016-04-26 136 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"');