@9StarRu

Как организовать пакетное добавление информации в базу данных?

Написал тяжелый скрипт, который получает информацию из XML файла, далее переходит по ссылке из файла и получает информацию с сайта на который перешел, возвращает полученную информацию в скрипт и сохраняет данные в базу MySQL.

В XML файле тысячи адресов с которых нужно получить дополнительную информация из-за чего я столкнулся с проблемой зависания скрипта не по причине нехватки памяти (причина мне не ясна, памяти достаточно свободной).

Из 6000 адресов, за пару часов скрипт добавляет в базу около 450 и останавливается.

Пожалуйста, помогите написать функцию, изменить скрипт таким образом, чтобы он отрабатывал все 6000 адресов не останавливаясь.

Я пробовал добавить sleep(SLEEP); но не смог корректно написать для этого функцию.

Код:

<?php
set_time_limit(0);

header('Content-type: text/html; charset=utf8');
ini_set("display_errors", "On");
require_once 'config.php';

/* Вариант 2. 2 строки ниже для вставки только новых значений(не заменяя старых) */
$Query = "INSERT IGNORE INTO `xml`(`id_xml`,`date_xml`,`title_xml`,`link_xml`) VALUES";
$ODKU = ';';

$values = "";
$text = "";

function page_title($url){
    $fp = file_get_contents($url);
    if (!$fp) 
        return null;

    $res = preg_match("/<title>(.*)<\/title>/siU", $fp, $title_matches);
    if (!$res) 
        return null; 

    // Clean up title: remove EOL and excessive whitespace.
    $title = preg_replace('/\s+/', ' ', $title_matches[1]);
    $title = trim($title);
    return $title;
}

// Получаем XML файл

$file = '/var/www/test.xml'; // сохраняем файл XML

$read = simplexml_load_file($file); // получаем объект класса из файла

$xml = $read->Category->Club;

$count = count($xml); // кол-во элементов массива


for($i = 0; $i < $count; $i++){

$text = page_title('https://test.com='.$xml[$i]->Id.'');    

$date_xml = mysql_real_escape_string($xml[$i]->Id);
$title_xml = mysql_real_escape_string($xml[$i]->Title);
$id_xml = mysql_real_escape_string($xml[$i]->Description);
$link_xml = mysql_real_escape_string($xml[$i]->Title);

if (strlen($text) > 0) {
    $link_xml = mysql_real_escape_string($text);
} else {
    $link_xml = mysql_real_escape_string($xml[$i]->Title);
}

//    sleep(SLEEP);

  $values .= "('$id_xml', '$date_xml','$title_xml','$link_xml'),";
  /* заносим данные в БД если накопилось 1000 записей при подготовке запроса */ 
  if($i % 1000 == 0)
  {
    $values[strlen($values)-1]=' ';
    $res = mysql_query("$Query $values $ODKU");
    $values = "";
  }

}

if(strlen($values)>0)
{
  $values[strlen($values)-1]=' ';
  /* заносим данные в БД */
  $res = mysql_query("$Query $values $ODKU");    
}

echo 'Done';


Спасибо!
  • Вопрос задан
  • 66 просмотров
Решения вопроса 1
@LemonFox
Fullstack
Во-первых, у вас нет обработки ошибок mysql

php.net/manual/ru/function.mysql-query.php

Во-вторых, используйте pdo/mysqli (благо musqli_* обратно совместим и перейти на него можно глобальной заменой по проекту) - mysql-расширение давно устарело

В-третьих, попробуйте использовать XMLreader, ибо simpleXML на больших объемах может упираться в лимиты памяти.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
DevMan
@DevMan
скрипты просто так не останавливаются. для этого есть ровно 3 основных причины:
1. ошибка (поэтому должен быть включен максимальный их вывод).
2. закончились данные (это может быть ошибка логики).
3. убит супервизором по лимитам.

что нужно сделать:
1. запускать в cli-режиме.
2. обойти весь файл и собрать урлы, сохранить их отдельно в базу.
3. полученные урлы грузить параллельно (мультикурл в помощь).
4. не нужно собирать данные в пачку: обработали контент - тут же записали его в базу, обработанный урл удалили из базы. это позволит в случае ошибки/падения не терять данные и не собирать повторно уже обработанные данные.
5. в 2019 году уже стоит похоронить mysql_* и не вспоминать.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через TM ID
Похожие вопросы