用json编码分块MySQL数组


Chunking MySQL array with json encode

我知道在php中存在一些关于分块mysql数组的问题,但我的问题是,我想保持JSON输出。

场景:我想从mysql中获取数据,用它做一些事情(如时间格式)并以JSON输出。JSON数据在浏览器中解析,并通过javascript图表可视化。

问题:以上所有的工作,但由于大量的数据,我得到一个内存不足的错误,当我选择更大的日期范围输出。

直接发送每个x行数据的想法是行不通的,因为它需要JSON格式。几个JSON块不能工作,它需要一个用于图表。

所以最后我需要将数据块化,但将其保留为一个大JSON。(设置内存限制并不是真正的解决方案。)

想法:一种想法是,让浏览器对日期范围进行分块,并以块的形式请求数据。然后把它们放在一起。当然,这是可行的,但是如果有一种方法可以在服务器端做到这一点,那就更好了。

代码:

private function getDB($date1, $date2){
    $query = 'SELECT * FROM `db1`.`'.$table.'` WHERE `date` BETWEEN "'.$date1.'" AND "'.$date2.'" order by `date`;';
    // date = datetime !
    $result = $this->db->query($query);
    $array = array();
    while ( $row = $result->fetch_assoc () ) {
        $array[] = array( strtotime($row[ 'date' ])*1000 , (float)$row[ 'var' ] );
        // the formatting needs to be done, so the chart accepts it..
    }
    $result->close();
    return json_encode($array);
}

由于这不是一个选项,

ini_set("memory_limit","32M")

也许你可以在函数参数和查询中添加LIMIT:

private function getDB($date1, $date2, $start, $pageSize){
    $query = 'SELECT * FROM `db1`.`'.$table.'` WHERE `date` BETWEEN "'.$date1.'" AND "'.$date2.'" order by `date` LIMIT $start, $pageSize;';
    // date = datetime !
    $result = $this->db->query($query);
    $array = array();
    while ( $row = $result->fetch_assoc () ) {
        $array[] = array( strtotime($row[ 'date' ])*1000 , (float)$row[ 'var' ] );
        // the formatting needs to be done, so the chart accepts it..
    }
    $result->close();
    return json_encode($array);
}

然后在javascript中设置一个for循环,用Ajax调用它,每次增加$start变量。

将每个responseText.substr(1).substr(-1)存储在一个数组中

当responseText为"时,表示已返回所有记录。

。用逗号连接数组,然后添加一个新的开始和结束"{}",你应该有一个相当于所有记录的JSON。

最小解析,并且您将使用内置函数进行大部分解析。

var startRec=0;
var pageSize=50;
var xmlhttp=new XMLHttpRequest();
var aryJSON=[];
var JSON;
xmlhttp.onreadystatechange=function(){
    if (xmlhttp.readyState==4 && xmlhttp.status==200){
        if(xmlhttp.responseText==""){ //Might need to check for "{}" here instead of ""
            //All records are received
            JSON="{" + aryJSON.join(",") + "}";
            aryJSON=[];
            startRec=0
        }else{
            aryJSON.push(xmlhttp.responseText.substr(1).substr(-1));
            startRec+=pageSize;
            getNextPage();
        }
    }
}
function getNextPage(){
    xmlhttp.open("GET","your.php?start=" + startRec + "&pageSize=" + pageSize,true);
    xmlhttp.send();
}

我建议让服务器向浏览器发送创建表所需的内容。解析可能是一项繁重的任务,那么为什么要让客户端执行这项任务呢?

我会让你的后端发送浏览器某种数据结构,表示表(即列表的列表),所有的格式已经完成。呈现表应该更快,内存占用更少。

一种答案是,在服务器上进行分块,通过给出JSON,删除前导[&] .

@apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);
$array = array();
echo '[';
$started = false;
while ( $row = $result->fetch_assoc () ) {
    $array[] = [ strtotime($row[ 'datetime' ])*1000 , (float)$row[ 'var' ] ];
    if(sizeof($array) == 1000){
        if($started){
            echo ',';
        }else{
            $started = true;
        }
        echo substr(substr(json_encode($array),1), 0, -1);
        // converting  [[datetime1, value1],[datetime2, value2]]
        //          to  [datetime1, value1],[datetime2, value2]
        ob_flush();
        $array = array();
    }
}
if($started)echo ',';
$this->flushJSON($array);
echo ']';
flush();
$result->close();

这正在工作并将ram使用率降低到40%。Apache似乎仍然在缓冲一些东西,所以随着时间的推移,脚本正在运行,内存使用量会增加。(是的,冲洗工作,我调试了,这不是问题。)

但是由于剩余的增量,实现干净分块的最快方法是像alfadog67指出的那样做。

另外,要提到它,我必须禁用输出压缩,否则apache不会直接刷新它。