Оптимизация вставки MySQL в фид XML-данных - PullRequest
1 голос
/ 03 декабря 2011

Я получаю XML-канал от компании каждую ночь и нуждаюсь в серьезной оптимизации, так как это требует вечности

Код ниже показывает, как я это делаю, но должен быть лучший способ - в основном, я принимаю каждыйпродукт, а затем связанные розничные продавцы, которые поставляют этот продукт

//db connect
include '../php/lib/dbconnect.inc';

$categories = array(1, 2, 4, 8, 9);

foreach ($arr as $key => $cat_id) { {

$url = "http://*********.com/feed?f=PRSP_UK_xx&categories=$cat_id&limit=100&startproducts=$ii&price_min=0.01&sortproducts=score&show=properties";
$c = curl_init($url); 
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_HEADER, 0);
curl_setopt($c, CURLOPT_USERPWD, "****:****");
$xml = simplexml_load_string(curl_exec($c));
curl_close($c);

$num_items = $xml->{'product-count'};

$ii = 0;

while ($ii <= $num_items) { // this sets the number of items from start of xml feed

    $url = "http://********.com/feed?f=PRSP_UK_xx&categories=$cat_id&limit=100&startproducts=$ii&price_min=0.01&sortproducts=score&show=properties";

    $c = curl_init($url); 
    curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($c, CURLOPT_HEADER, 0);
    curl_setopt($c, CURLOPT_USERPWD, "****:****");
    $xml = simplexml_load_string(curl_exec($c));
    curl_close($c);

// load each product first

    foreach ($xml->product as $products) {

$title = $products->name;

$title = preg_replace('/[^a-z0-9\s]/i', '', $title);

$PRid = $products->id;

$author = $products->properties->group->property[2]->value;

$author = preg_replace('/[^a-z0-9\s]/i', '', $author);

$genre = $products->properties->group->property[4]->value;

$genre = preg_replace('/[^a-z0-9\s]/i', '', $genre);

$prodcat = $products->{'category'};

$prodcat = preg_replace('/[^a-z0-9\s]/i', '', $prodcat);

$prodcatID = $products->{'category-id'};

$lowprice = $products->{'lowest-price'};

$highprice = $products->{'highest-price'};

$imageURL = $products->{'image-url'};

$userrating = $products->rating[0]->average;

$userrating = str_replace(",",".",$userrating);

$profrating = $products->rating[0]->average;

$profrating = str_replace(",",".",$profrating);

    $addline = mysql_query("
    insert into PRprodINFO (
    PRid,
    main_category,
    title,
    author,
    genre,
    prodcat,
    prodcatID,
    userrating,
    profrating,
    lowprice,
    highprice,
    imageURL
    )
        VALUES (
    '$PRid',
    'Books',
    '$title',
    '$author',
    '$genre',
    '$prodcat',
    '$prodcatID',
    '$userrating',
    '$profrating',
    '$lowprice',
    '$highprice',
    '$imageURL'
    ) ON DUPLICATE KEY UPDATE lowprice='$lowprice', highprice='$highprice'",$db);

    if(!$addline) { echo "cannot add to table here".mysql_error(); exit; } // debug

    // now each retailer associated with the product

    foreach ($products->retailer as $retailer) {

    $id = $retailer->{'id'};

    $name = $retailer->{'name'};

    $name = addslashes($name);

    $link = $retailer->{'link'};

    $logoURL = $retailer->{'logo'};

    $stockinfo = $retailer->{'stock-info'};

    $price = $retailer->{'price'};

    $priceshipmin = $retailer->{'price-with-shipping-min'};

    $priceshipmax = $retailer->{'price-with-shipping-max'};

    $dummyid = $PRid.$id;

    $id = preg_replace('/[^a-z0-9\s]/i', '', $id);

    $stockinfo = preg_replace('/[^a-z0-9\s]/i', '', $stockinfo);

    $dummyid = preg_replace('/[^a-z0-9\s]/i', '', $dummyid);

    $addretail = mysql_query("
    insert into PRretailerinfo (
    PRid,
    id,
    dummyid,
    category_id,
    name,
    link,
    logoURL,
    stockinfo,
    price,
    priceshipmin,
    priceshipmax
    )
        VALUES (
    '$PRid',
    '$id',
    '$dummyid',
    '$i',
    '$name',
    '$link',
    '$logoURL',
    '$stockinfo',
    '$price',
    '$priceshipmin',
    '$priceshipmax'
    ) ON DUPLICATE KEY UPDATE price='$price', priceshipmin='$priceshipmin', priceshipmax='$priceshipmax'",$db);

    if(!$addretail) { echo "cannot add to table - price is".$price.mysql_error(); exit; } // debug

} // close
} // close

    // add 100 to url to get next 100 items
$ii = ($ii+100);

}

} // whole thing

Я бы предположил, что есть гораздо лучший способ сделать это, чем построчно, поскольку в целом это около 800 000 товаров и, в среднем, 4 розничных торговца длякаждый продукт

Я считаю, что быстрее построить длинный запрос, используя несколько строк перед вставкой, но я не могу найти способ сделать это.

Ответы [ 2 ]

1 голос
/ 03 декабря 2011

Скорее всего, медлительность не связана с выполнением нескольких запросов на вставку, но скорее всего из-за огромного количества http-запросов, которые вы делаете для получения данных. Есть ли способ получить больше данных с сервера сразу?

.... Возможно, измените параметр получения товара с лимита = 100 на лимит = $ num_items

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

0 голосов
/ 03 декабря 2011

Я не думаю, что вы можете сделать вставку из нескольких записей и все еще использовать mysql для функции обновления дубликатов ключей ...

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

Используйте microtime (), чтобы найти медленную часть вашего скрипта. Производительность базы данных, вероятно, незначительна по сравнению с сетью (загрузка).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...