Autor Zpráva
Taps
Profil
Zdravím, mám XML soubor o velikosti 3 MB, z tohoto souboru potřebuji vyseparovat data a provést aktualizaci údajů v databázi. V databázi má proběhnout update cca 2000 produktů. Pokud níže uvedený skript spustím, tak pracuje velmi dlouho a pak se zobrazí chyba serveru - 500. Existuje nějaká možnost jak skript zoptimalizovat, tak, aby v krátké časové době provedl parsování xml souboru a update produktů v databázi?

Skript
<?php
ini_set("display_errors", 1);
error_reporting(E_ERROR | E_WARNING);
include './inc/config.php';

    $reader = new XMLReader();
    copy("http://web/file.xml", "file.xml");
    
    $reader->open("file.xml");
     
    while($reader->read())
    {
    if($reader->nodeType == XMLReader::ELEMENT) $nodeName = $reader->name;
    if($reader->nodeType == XMLReader::TEXT || $reader->nodeType == XMLReader::CDATA)
    {
    if ($nodeName == 'KOD')  $code = 'PCD-014-'.$reader->value;
    if ($nodeName == 'STOCK') $stock = $reader->value;

$vlozeno = mysql_query("UPDATE t5jfw_virtuemart_products SET product_in_stock = '$stock' WHERE product_sku = '$code'");
  
    }
     
    if($reader->nodeType == XMLReader::END_ELEMENT && $reader->name == 'SHOP')
    {
    $count++;
    }
    }
    $reader->close();
 echo ($count>0)  ? 'OK - vloženo '.$count.' záznamů' : 'CHYBA';
?>

Děkuji
juriad
Profil
Taps:
Jak dlouho to trvá, pokud vyhodíš UPDATE v databázi. Prostě jen projít celý xml soubor.
Je napřed potřeba vědět, zda je trvá dlouho operace se souborem, či s databází. Tipuji to druhé.


Vytvoř si tempovou tabulku:
CREATE TABLE t5jfw_virtuemart_products_tmp AS SELECT * FROM t5jfw_virtuemart_products WHERE 1=2;
Následně budeš do této tabulky provádět INSERTy vžy třeba stovky produktů najednou:
INSERT INTO t5jfw_virtuemart_products (product_sku, product_in_stock) VALUES
(pr1, st1), (pr2, st2), (pr2, st2), (pr3, st3), ...
Pak jedním dotazem změníš všechny hodnoty v původní tabulce najednou:
UPDATE t5jfw_virtuemart_products p
JOIN t5jfw_virtuemart_products_tmp tmp ON p.product_sku = tmp.product_sku
SET p.product_sku = tmp.product_sku
A na závěr buď:
DROP TABLE t5jfw_virtuemart_products_tmp
nebo (pokud tu tabulku chceš nechat, abys ji příště nemusel vytvářet:
TRUNCATE TABLE t5jfw_virtuemart_products_tmp

Nebo to také jde udělat (http://stackoverflow.com/a/3466/4052811):
INSERT IGNORE ... ON DUPLICATE KEY UPDATE ... 

V každém případě se ti nejspíš nepodaří UPDATEnout všech 2000 řádků najednou, budeš to muset rozdělit do bloků.
Výhodou prvního způsobu je izolovanost; v té tabulce nejsou klíče a indexy, takže insert je rychlý; tento způsob lze použít na libovolné databázi. Výhodu druhého je snadnost použití. Toto bude fungovat jen na mysql
Tori
Profil
Nedalo by se vygenerovat .sql soubor a pak ho spustit přes LOAD DATA INFILE? A redukovat počet SQL příkazů použitím hromadného INSERT + ON DUPLICATE KEY?
Taps
Profil
juriad:
Procházení samotného xml souboru trvá 0.3 s
S postupem dle http://stackoverflow.com/questions/3432/multiple-updates-in-mysql/3466#3466 doba trvání 8.63 s
Jan Tvrdík
Profil
Taps:
A je určitě potřeba aktualizovat ty produkty všechny? Není to tak, že většina produktů je beze změny a stačí jich aktualizovat jen výrazně menší část?

doba trvání 8.63 s
A to už je pro tebe dostatečně rychlé nebo to pořád potřebuješ zrychlit?

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: