memory — PHP: чтение и экспорт больших данных без изменения memory_limit & amp; max_execution_time

У меня есть много данных для экспорта в CSV-файл. Моя функция зацикливается на каждом поле и выполняет функцию для получения данных из таблицы SQL.
Теперь у меня очень большая база данных, и я хочу экспортировать некоторые данные без изменения конфигурации memory_limit, потому что я не хочу блокировать других пользователей.

Как я могу сделать, чтобы выполнить свою функцию?

Например :
У меня есть 100000 человек, и у каждого человека есть много версий некоторых данных. Каждый день они сохраняют такую ​​информацию:

Person Table
+-----------+-------------+-------------+
| id_person | name_person | city_person |
+-----------+-------------+-------------+
| 1         | Jack        | Paris       |
+-----------+-------------+-------------+
| 2         | John        | London      |
+-----------+-------------+-------------+
| ...       | ...         | ...         |
+-----------+-------------+-------------+
| 99999     | Rose        | Madrid      |
+-----------+-------------+-------------+
| 100000    | Jackie      | Rome        |
+-----------+-------------+-------------+

Field Table
+----------+------------+-------------------+
| id_field | name_field | label_field       |
+----------+------------+-------------------+
| 1        | Location   | Visited location  |
+----------+------------+-------------------+
| 2        | Article    | Count of articles |
+----------+------------+-------------------+
| ...      | ...        | ...               |
+----------+------------+-------------------+
| 289      | Distance   | Distance          |
+----------+------------+-------------------+
| 299      | Pause      | Time of pause     |
+----------+------------+-------------------+

Field Value Table
+----------+----------+-----------+----------------+------------+
| id_value | id_field | id_person | value          | Date       |
+----------+----------+-----------+----------------+------------+
| 1        | 1        | 148       | Hanover Street | 2015-05-10 |
+----------+----------+-----------+----------------+------------+
| 2        | 66       | 57962     | 20             | 2015-05-10 |
+----------+----------+-----------+----------------+------------+
| ...      | ...      | ...       | ...            |            |
+----------+----------+-----------+----------------+------------+
| 3475992  | 105      | 847       | 17,5           | 2018-02-01 |
+----------+----------+-----------+----------------+------------+
| 3475993  | 15       | 66359     | 44             | 2018-02-01 |
+----------+----------+-----------+----------------+------------+

Каждое поле имеет определенную функцию для получения данных.

Как я могу получить все данные для экспорта в CSV-файл без изменения лимита памяти?

Спасибо

-1

Решение

Используйте небуферизованные запросы, неявную очистку, отправляйте данные непосредственно в выходной буфер (для загрузок), используйте CLI (для экспорта файлов). Отключите / увеличьте временные ограничения (если необходимо) только для этого сценария, а не для всего мира.

http://php.net/manual/en/mysqlinfo.concepts.buffering.php

http://php.net/manual/en/wrappers.php.php

Как сбросить вывод после каждого вызова `echo`? (ответ @Roger)

http://php.net/manual/en/function.set-time-limit.php

Это слишком много кода для меня, чтобы написать все это, и слишком много неизвестного. Например, какую БД вы используете (MySQL, MsSQL и т. Д.), Какие классы БД, PDO или MySqli? Вы экспортируете в файл на сервере или скачиваете. Вы хотите данные как CSV, SQL и т. Д.

  • Не буферизация запроса обойдется дороже, займет больше времени, но лучше управляет памятью и лучше обрабатывает большие таблицы.
  • Неявная очистка сохраняет небольшой размер выходного буфера (управление памятью).
  • Отправить данные на php://output лучшее управление памятью и более эффективный.
  • Ограничение по времени должно быть очевидным.

Моя функция зацикливается на каждом поле и выполняет функцию для получения данных из таблицы SQL.

Используйте Joins вместо многократного вызова БД, используйте правильные индексы для ваших таблиц.

Это нормально использовать ini_set('memory_limit' ...) а также set_time_limit потому что они влияют только на текущий процесс PHP, и не являются глобальными. Очевидно, что лучше избегать их, если можете, но иногда это просто невозможно.

Самый быстрый способ экспорта mysqldump:

https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html

Но у него есть ограничения (например)

https://dba.stackexchange.com/questions/4654/is-it-possible-to-mysqldump-a-subset-of-a-database-required-to-reproduce-a-query

Вы не можете экспортировать с помощью JOIN, и сложные запросы станут очень сложными, потому что я думаю, что вы можете использовать только основные --where вызов, без агрегации .. и т. д.

0

Другие решения

Существует два способа чтения и экспорта больших данных.

  • Посредством пакетного процесса — разделите объемные данные на куски и используйте спать
    затем продолжите следующий блок для обработки.
  • Через элементы очереди в базу данных

ОБРАЗЕЦ КОДА

$con = 'mysql:host=localhost;dbname=example';
$username = 'example';
$password = 'example';
$pdo = new PDO($con, $username, $password);

$i = !empty($_GET['pass']) ? (int) $_GET['pass'] : 0;

$string = "SELECT * FROM users LIMIT $i,10";
$query = $pdo->prepare("$string");
$query->execute();
// This would not fill memory anymore.
$results = $query->fetchAll();
// Nothing to do, we have finished.
if (!count($results)) {
return;
}
foreach ($results as $result) {
// Perform lengthy operation.
sleep(1);
}

$i++;
// Send request back to process next execution.
$redirect = $_SERVER['DOCUMENT_URI'] . '?pass=' . $i;
header("Location: $redirect");
exit();
0

Попробуйте этот экспорт через команды

mysqldump -p -u username database_name > dbname.csv
-1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector