PHP File Writing (fwrite / file_put_contents) скорость / оптимизация

Итак, у меня есть база данных с большими данными. Данные для использования в настоящее время около 2,6 ГБ.

Все данные должны быть записаны в текстовый файл для последующего использования в других сценариях.

Данные ограничены для каждого файла и разделены на несколько частей. 100 результатов на файл (около 37 МБ каждый файл). Это около 71 файлов.

Данные представляют собой данные json, которые сериализуются, а затем шифруются с помощью openssl.

Данные правильно записываются в файлы, пока максимальное время выполнения не будет достигнуто через 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);

1 ответ

Решение

Лично я бы закодировал это как один 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()

У меня была мысль, основанная на вашем комментарии о времени исполнения. Если вы разместите set_time_limit(seconds) внутри if внутри while цикл может быть чище, и вам не придется устанавливать ini_set('max_execution_time', 600); к очень большому числу, которое, если у вас есть настоящая ошибка, может заставить PHP продолжить обработку в течение долгого времени, прежде чем выкинуть скрипт.

Из руководства:

Установите количество секунд, в течение которых скрипт может быть запущен. Если это достигнуто, скрипт возвращает фатальную ошибку. Ограничение по умолчанию составляет 30 секунд или, если оно существует, значение max_execution_time, определенное в php.ini.

При вызове set_time_limit() сбрасывает счетчик тайм-аута с нуля. Другими словами, если время ожидания составляет 30 секунд по умолчанию и 25 секунд на выполнение сценария выполняется вызов, такой как set_time_limit(20), сценарий будет работать в общей сложности 45 секунд до истечения времени ожидания.

Другие вопросы по тегам