PHP: чтение и экспорт больших данных без изменения memory_limit & max_execution_time - PullRequest
0 голосов
/ 22 октября 2018

У меня есть много данных для экспорта в 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-файл без изменения лимитапамять?

Спасибо

Ответы [ 3 ]

0 голосов
/ 22 октября 2018

Используйте небуферизованные запросы, неявную очистку, отправляйте данные непосредственно в выходной буфер (для загрузок), используйте 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 голосов
/ 22 октября 2018

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

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

SAMPLE CODE

$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 голосов
/ 22 октября 2018

Попробуйте этот экспорт с помощью команд

mysqldump -p -u username database_name > dbname.csv
...