【问题标题】:Creating HTML files from huge table data从庞大的表格数据创建 HTML 文件
【发布时间】:2011-11-01 23:45:03
【问题描述】:

我的最终目标是将发票创建为我正在处理的计费项目的 PDF - 创建 PDF 是我已经完成的事情 - 我首先为每个发票创建一个 HTML 文件,然后在单独的过程中将 HTML 批处理为 PDF .

然后我遇到的问题是我试图进入 HTML 文件的数据非常大......它存储在 MySQL 中(我使用 Symfony 1.4 和 Doctrine)。 php.ini 当前设置为允许 500M 内存用于 php。我需要在同一个 HTML/PDF 文件中包含一张发票的所有 invoiceLines。

我目前正在循环一个发票表(每张发票 1 行),然后从另一个表(每张发票很多行)获取发票的实际行 - 我遇到的问题是内存使用量很大 - 任何人都可以建议这样做的替代方法。

foreach ($invoices as $inv)
{
    $outfile = '/ivoice' . $inv[0] . '.html';

    $tempinvfile = fopen($outfile, 'w'); //open file and replace current it exists

    echo '1 - Used memory : ' . number_format(memory_get_usage() - $mem) . PHP_EOL;

    $invoiceLines = Doctrine::getTable('InvoiceLine')
            ->createQuery()
            ->where('invoiceid = ?', $inv[0])
            ->setHydrationMode(Doctrine::HYDRATE_NONE)
            ->execute();

    echo "Count = " . count($invoiceLines) . PHP_EOL;

    echo '2 - Used memory : ' . number_format(memory_get_usage() - $mem) . PHP_EOL;

    $bodyhtml = '';
    foreach ($invoiceLines as $invline)
    {
//        $bodyhtml .= '<tr>';
//        $bodyhtml .= '    <td><b>' . $invline[2] . '</b></td>';
//        $bodyhtml .= '    <td>&pound;' . $invline[4] . '</td>';
//        $bodyhtml .= '    <td>&pound;' . $invline[5]. '</td>';
//        $bodyhtml .= '    <td>&pound;' . $invline[8] . '</td>';
//        $bodyhtml .= '    <td>&pound;' . $invline[9] . '</td>';
//        $bodyhtml .= '    <td>&pound;' . $invline[10] . '</td>';
//        $bodyhtml .= '    <td>&pound;' . $invline[12] . '</td>';
//        $bodyhtml .= '</tr>';
    }
    echo '3 - Used memory : ' . number_format(memory_get_usage() - $mem) . PHP_EOL;
//          fwrite($tempinvfile, $bodyhtml);
//          fclose($tempinvfile);
}

echo 'Used memory : ' . number_format(memory_get_usage() - $mem) . PHP_EOL;

echo "Done processing, time = " . (time() - $start) . PHP_EOL;

这产生的输出如下:

Starting Processing
1 - Used memory : 615,736
Count = 39
2 - Used memory : 1,033,264
3 - Used memory : 1,033,344
after end loop - Used memory : 1,033,344
1 - Used memory : 1,055,448
Count = 11
2 - Used memory : 1,118,200
3 - Used memory : 1,118,200
after end loop - Used memory : 1,118,200
1 - Used memory : 1,140,304
Count = 30340
2 - Used memory : 89,061,552
3 - Used memory : 88,977,472
after end loop - Used memory : 88,977,472
1 - Used memory : 88,999,576
Count = 156
2 - Used memory : 89,482,752
3 - Used memory : 89,482,752
after end loop - Used memory : 89,482,752
1 - Used memory : 89,505,368
Count = 3867
2 - Used memory : 100,737,248
3 - Used memory : 100,737,248
after end loop - Used memory : 100,737,248
Used memory : 100,737,248
Done processing, time = 0

所以我可以清楚地看到,主要的内存使用是在从表中抓取 invoiceLines 时。但是我不知道解决这个问题的最佳方法.....如何在每个循环结束时回收内存?

我曾尝试使用 DoctrinePager 并一次循环一页 - 有效,但使用的内存比上述方法更多。

非常欢迎提出建议.....

编辑:

所有文件操作都被注释掉并且在 echo 3 之后添加了 unset($invoiceLines) 的内存输出:

Starting Processing
1 - Used memory : 615,712
Count = 39
2 - Used memory : 1,033,248
3 - Used memory : 1,033,328
after end loop - Used memory : 1,033,328
1 - Used memory : 1,055,432
Count = 11
2 - Used memory : 1,118,176
3 - Used memory : 1,118,176
after end loop - Used memory : 1,118,176
1 - Used memory : 1,140,280
Count = 30340
2 - Used memory : 89,061,760
3 - Used memory : 88,977,680
after end loop - Used memory : 88,977,680
1 - Used memory : 88,999,784
Count = 156
2 - Used memory : 89,482,968
3 - Used memory : 89,482,968
after end loop - Used memory : 89,482,968
1 - Used memory : 89,505,584
Count = 3867
2 - Used memory : 100,737,464
3 - Used memory : 100,737,464
after end loop - Used memory : 100,737,464
Used memory : 100,737,464
Done processing, time = 0

编辑 2:@Crack 的建议 -> 在 databases.yml 文件中添加了 profiler:false .. 这是内存结果:

Starting Processing
1 - Used memory : 600,392
Count = 39
2 - Used memory : 1,006,768
3 - Used memory : 1,006,848
after end loop - Used memory : 896,352
1 - Used memory : 903,192
Count = 11
2 - Used memory : 954,624
3 - Used memory : 951,824
after end loop - Used memory : 922,576
1 - Used memory : 929,416
Count = 30340
2 - Used memory : 88,840,104
3 - Used memory : 88,751,672
after end loop - Used memory : 863,168
1 - Used memory : 870,008
Count = 156
2 - Used memory : 1,342,816
3 - Used memory : 1,340,016
after end loop - Used memory : 889,392
1 - Used memory : 896,232
Count = 3867
2 - Used memory : 12,117,080
3 - Used memory : 12,114,280
after end loop - Used memory : 915,616
Used memory : 915,616
Done processing, time = 0

【问题讨论】:

  • 你能在第三次回声后尝试取消设置($invoiceLines) 和 fclose($tempinvfile),然后告诉我们区别吗?
  • @corretge - 注释掉文件操作行并添加未设置 - 结果高于...

标签: php mysql symfony1 doctrine


【解决方案1】:

在读取 1000 行后使用 fwrite(),然后重置 $bodyhtml ($bodyhtml = '';)。这样你就不会在内存中存储一​​个大字符串。

编辑

糟糕,Doctrine 必须将所有先前读取的行存储在 $invoiceLines 的某个缓存中...尝试查看 php/symfony/doctrine memory leak? 的解决方案。

【讨论】:

  • 它不是导致内存被消耗的 $bodyhtml - 它是查询的结果 - 你能告诉我如何一次只循环 1000 行......我尝试使用 DoctrinePager - 但是这给出了与 Question 中相似的内存使用情况
  • 正确的解决办法是看能不能对Doctrine的内存使用做点什么。如果没有,您可以将LIMIT 应用于您的查询并在几遍中生成 HTML。
  • 我只是在考虑使用 Limit / Offset - 然后循环直到我在 HTML 文件中拥有整个行集合 - 但问题更多是内存没有恢复 - 我有 4000 张发票创建...
  • 也许这会有所帮助 - stackoverflow.com/questions/2097744/… ?
  • HOLY S&*T ...感谢您 - profiler: false 产生了巨大的影响 - 在问题中发布了结果 ....
猜你喜欢
  • 2012-04-20
  • 1970-01-01
  • 1970-01-01
  • 2013-04-24
  • 1970-01-01
  • 1970-01-01
  • 2016-05-22
  • 2023-04-05
  • 2020-10-28
相关资源
最近更新 更多