PHP逐行回显json_encode而不是最后解决内存问题,这是一个坏主意吗?

时间:2019-02-14 01:59:13

标签: php mysql json

我需要以JSON格式输出至少500,000条记录,最初使用的是以下内容

<?php

  $con=mysqli_connect("localhost",$username,$password,databaseName);

  // Check connection
  if (mysqli_connect_errno())
  {
   echo "Failed to connect to MySQL: " . mysqli_connect_error();
  }

  $query = "the query here";

  $result = mysqli_query($con,$query);

  $rows = array();
  while($r = mysqli_fetch_array($result)) {
    $rows[] = $r;
  }
  echo json_encode($rows);

  mysqli_close($con);
?>

也就是说,我将所有内容存储在变量中,然后在最后输出。


但是我发现在记录很大的情况下,我遇到了内存不足错误Allowed memory size of xxxxx bytes exhausted (tried to allocate xx bytes)

然后,我修改了上述内容以解决以下问题:

<?php
  //Same as above

  $result = mysqli_query($con,$query);
  $numItems = mysql_num_rows($result);
  $i = 0;
  echo "[";
  while($r = mysqli_fetch_array($result)) {
    echo json_encode($r);
    if(++$i !== $numItems) {
       echo ",";
    }
  }
  echo "]";

  mysqli_close($con);
?>

我没有在最后输出行,而是在每次MySQL迭代期间输出每一行。因此,无需将所有行都存储在变量缓冲区中。

对于我拥有的50万行记录,它运行得很好。但是,当我在线搜索时,没有人做我做的事情。所以我的问题是:

  1. 我的逐行echo json_encode()方法可以安全使用吗?
  2. 如果否,是否有更好的方法来解决内存不足的问题? (资源有限,不能选择增加内存)

1 个答案:

答案 0 :(得分:2)

由于您没有足够的内存将整个JSON文档保存在内存中,因此请考虑使用一种更有效的内存替代方法:

将每一行作为一个简单的数组转储出来,这样可以避免重复每一行的键。例如,代替:

[
  { "id": 1, "valueA": "A", ... },
  { "id": 2, "valueA": "A", ... },
  ...
]

考虑这样做:

{
  "columns": [ "id", "valueA", ... ],
  "values": [
    [ 1, "A" ],
    [ 2, "A" ],
    ...
  ]
}

实际上会导致大大个较小的文档。

您可能还想考虑使用JSON Streaming或行分隔的JSON,在其中每行输出一个文档

{ "id": 1, "valueA": "A", ... }
{ "id": 2, "valueA": "A", ... }

虽然不会减少结果的整体大小,但确实可以简化另一端的解析。阅读器仅需要足够的内存来容纳最大的单行文档,而不是一次存储所有500K。

如果您的Web服务器支持流式传输结果,这也可能会带来性能上的好处,因为您可以在所有记录都加载之前开始传输记录。

考虑:如果您没有足够的内存来完整地生成文档,那么如果没有手边的 ton 内存,有人怎么能使用它呢?行分隔的JSON更加易于阅读,您可以将其流式传输,快速对其进行迭代。