PHP 文件写入 (fwrite / file_put_contents) 速度/优化


PHP File Writing (fwrite / file_put_contents) speed/optimization

所以,我有一个包含大数据的数据库。要使用的数据目前约为 2,6 GB。

所有数据都需要写入文本文件,以便以后在另一个脚本中使用。

每个文件的数据受到限制,并分成多个部分。 每个文件 100 个结果(每个文件约 37MB)。这大约是 71 个文件。

数据是正在序列化然后使用 openssl 加密的 json 数据。

数据被正确写入文件,直到在 240 秒后达到最大执行时间。那是在大约 20 个文件之后...

好吧,我可以延长那个时间,但这不是问题。

问题如下:

Writing file 1-6:   +/- 5 seconds
Writing file 7-8:   +/- 7 seconds
Writing file 9-11:  +/- 12 seconds
Writing file 12-14: +/- 17 seconds
Writing file 14-16: +/- 20 seconds
Writing file 16-18: +/- 23 seconds
Writing file 19-20: +/- 27 seconds
Note: time is needed time per file
换句话说,随着每个文件的写入,

每个文件的写入时间显着增加,这导致脚本运行缓慢。

脚本的结构有点像这样:

$needed_files = count needed files/parts
for ($part=1; $part<=$needed_files; $part++) { // Loop throught parts
    $query > mysqli select data
    $data > json_encode > serialize > openssl_encrypyt
    file_put_contents($filename.$part, $data, LOCK_EX);
}

帮助后的工作代码

$notchDetails = mysqli_query($conn, "SELECT * FROM notches WHERE projectid = ".$projectid."");
$rec_count = 0;
$limit = 100;
$part = 1;
while ($notch = mysqli_fetch_assoc($notchDetails)) {
    $data1[] = $notch;
    $rec_count++;
    if ($rec_count >= $limit) {
        $data = json_encode($data1);
        $data = openssl_encrypt(bin2hex($data), "aes128", $pass, false, $iv);
        $filename = $mainfolder."/".$projectfolder."/".$subfolder."/".$fname.".part".$part."".$fext;
        file_put_contents($filename, $data, LOCK_EX);
        $part++;
        $rec_count = 0;
        $data = $data1 = "";
    }
}
if ($data1 != "") {
    $data = json_encode($data1);
    $data = openssl_encrypt(bin2hex($data), "aes128", $pass, false, $iv);
    $filename = $mainfolder."/".$projectfolder."/".$subfolder."/".$fname.".part".$part."".$fext;
    file_put_contents($filename, $data, LOCK_EX);
}
mysqli_free_result($notchDetails);

就我个人而言,我会将其编码为没有限制的单个 SELECT,然后基于$rec_per_file = ?;从单个 while get results 循环中写入输出

请原谅神秘的代码,您没有给我们太多线索

<?php
//ini_set('max_execution_time', 600);    // only use if you have to
$filename = 'something';
$filename_suffix = 1;
$rec_per_file = 100;
$sql = "SELECT ....";
Run query
$rec_count = 0;
while ( $row = fetch a row ) {
    $data[] = serialize > openssl_encrypyt
    $rec_count++;
    if ( $rec_count >= $rec_per_file ) {
        $json_string = json_encode($data);
        file_put_contents($filename.$filename_suffix, 
                          $json_string, 
                          LOCK_EX);
        $filename_suffix++; // inc the suffix
        $rec_count = 0;     // reset counter
        $data = array();    // clear data
        // add 30 seconds to the remaining max_execution_time
        // or at least a number >= to the time you expect this
        // while loop to get back to this if statement
        set_time_limit(30);
    }
}
// catch the last few rows
$json_string = json_encode($data);
file_put_contents($filename.$filename_suffix, $data, LOCK_EX);

我也不确定你为什么要serialize()json_encode()

根据您对执行时间的评论,我有一个想法。如果你在while循环内的if内放置一个set_time_limit(seconds),它可能更干净,并且你不必将ini_set('max_execution_time', 600);设置为一个非常大的数字,如果你在这里有一个真正的错误,可能会导致 PHP 在踢出脚本之前继续处理很长时间。

从手册:

设置允许脚本运行的秒数。如果达到此目的,脚本将返回致命错误。默认限制为 30 秒,或者,如果存在,则为 php.ini 中定义的max_execution_time值。

调用时,set_time_limit() 从零重新启动超时计数器。换句话说,如果超时是默认的 30 秒,并且在脚本执行 25 秒后进行了诸如 set_time_limit(20) 之类的调用,则脚本将在超时之前总共运行 45 秒。