Задать вопрос
@arsenaljek

Запись больших xml в MYSQL?

Помогите с проблемой.
Есть xml-каталоги. 14 штук. Суммарный их объем составляет 1.4гб. Я оттуда парсю товары. Структура обычный YML.
Скрипт скачивает их на сайт, затем в цикле foreach обходит каждый файл.
И так-как в скрипте есть еще условия, что если текущая цена, которая парситься, отличаеться от цены за вчера, то идет запись, иначе запись не производим. То выполнения скрипта происходит нереально долго. Я даже не уверен, что он вообще успевает все пройти, т.к ограничения работы скрипта ограничены 10 часами.
$dir = "xml/";
$files = scandir($dir);
$files = array_diff(scandir($dir), array('..', '.')); 
 foreach ($files as $key => $value) { 
   $z->open('xml/'.$value);
  $doc = new DOMDocument;
  while ($z->read() && $z->name !== 'offer');
  while ($z->name === 'offer') {
    $node = simplexml_import_dom($doc->importNode($z->expand(), true));
    $id = mysqli_real_escape_string($link6,$node['id']);
    $url = mysqli_real_escape_string($link6,$node->url);
    $price = $node->price;
    $sql = 'INSERT INTO products (`id`,`url`,`date`) VALUES ("'.$id.'","'.htmlspecialchars(urldecode($url)).'","'.$today.'")';
  $result = mysqli_query($link6,$sql);
  $new_price = (int)$price;

  $sql = 'SELECT * FROM prices WHERE id = '.$id.'  ORDER BY date DESC ';
  $result = mysqli_query($link6,$sql);
  $row = mysqli_fetch_array($result);
  if ($row['id'] == $id AND $row['date'] == $today_new OR $row['price_product'] == $price) {
    // echo 'все совпало</br>';
    $articles1[] = $row['id'];
  } else {
    $articles2[] = $row['id'];
    // echo 'несовпало</br>';
    if ($row['price_product'] == $new_price) {
      // echo 'не пишем дата сегоднящная уже записана';
    } else {
      $sql = 'INSERT INTO prices (`id`, `price_product`, `date`) VALUES ("'.$id.'","'.(int)$price.'","'.$today.'")';
      $result = mysqli_query($link6,$sql);
    }
  }
  $z->next('offer');
  }
 }


Можете подсказать, как оптимизировать. Увеличив скорость записи в бд? И правильно ли делать так, как делаю я?
  • Вопрос задан
  • 466 просмотров
Подписаться 2 Простой 1 комментарий
Решения вопроса 1
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Жжжуть. Делать выборку в цикле для каждой строки, да ещё и генерируя каждый раз запрос - это, наверно, худший из возможных вариантов.
В таблицу `products` добавляете колонку `price`. Вешаете на эту таблицу триггеры на вставку и изменение строки, которые при добавлении или изменении цены заносят её в таблицу `prices`. Напрямую с таблицей `prices` из этого скрипта не работаете.
В цикле формируете и накапливаете наборы данных для вставки. Как только накопится некоторое количество, вставляете их одним запросом. Используете ON DUPLICATE KEY UPDATE для перезаписи изменённых значений. По окончании цикла выгружаете оставшиеся наборы.
Примерно так
$data = [];
while ($z->name === 'offer') {
  ...
  $data[] = '("'.$id.'","'.htmlspecialchars(urldecode($url)).'","'.$today.'",'.(int)$price.')';
  if (count($data) > 99) {
    $sql = 'INSERT INTO `products` (`id`,`url`,`date`,`price`) VALUES ' 
         . implode(',', $data)
         . 'ON DUPLICATE KEY UPDATE `url` = VALUES(`url`), `price` = VALUES(`price`)';
    mysqli_query($link6,$sql);
    $data = [];
  }
  ...
}
if (count($data) > 0) {
  $sql = 'INSERT INTO `products` (`id`,`url`,`date`,`price`) VALUES ' 
       . implode(',', $data)
       . 'ON DUPLICATE KEY UPDATE `url` = VALUES(`url`), `price` = VALUES(`price`)';
  mysqli_query($link6,$sql);
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

Похожие вопросы