[ gotivac @ 23.10.2012. 10:55 ] @
Imam jedan problem koji umem da rešim, ali rešenje koje mi je palo na pamet radi previše sporo.
Radi se o aplikaciji koja se vrti na standardnoj LAMP konfiguraciji, i za koju je potrebno napraviti modul preko koga će korisnik jednom sedmično učitavati veliki xml fajl - radi se o tabeli osiguranika RFZO.

XML fajl ima sledeću strukturu:

Code:

<?xml version="1.0" encoding="windows-1250"?>
<Osiguranici>
<Osiguranik>
  <Filijala><![CDATA[ *******]]></Filijala>
  <Ispostava><![CDATA[ *******]]></Ispostava>
  <LBO><![CDATA[*******]]></LBO>
  <BrojKnjizice><![CDATA[*******]]></BrojKnjizice>
  <JMBG><![CDATA[*******]]></JMBG>
  <Prezime><![CDATA[*******]]></Prezime>
  <Ime><![CDATA[*******]]></Ime>
  <OsnovOsiguranja><![CDATA[*******]]></OsnovOsiguranja>
</Osiguranik>
<Osiguranik>
  <Filijala><![CDATA[ *******]]></Filijala>
  <Ispostava><![CDATA[ *******]]></Ispostava>
  <LBO><![CDATA[*******]]></LBO>
  <BrojKnjizice><![CDATA[*******]]></BrojKnjizice>
  <JMBG><![CDATA[*******]]></JMBG>
  <Prezime><![CDATA[*******]]></Prezime>
  <Ime><![CDATA[*******]]></Ime>
  <OsnovOsiguranja><![CDATA[*******]]></OsnovOsiguranja>
</Osiguranik>

... i tako dalje...

</Osiguranici>


(Zvezdice su naravno umesto pravih podataka osiguranika).

Pokušao sam ovo da rešim na dva načina - prvi je uz pomoć samog MySQL-a, to jest komande LOAD XML INFILE ... ali to neće da radi zbog ovih CDATA gluposti.

Drugi način koji radi bez problema je preko simplexml_load_file, ali tu sad nastaje frka.
Nisam hteo da čitam slog po slog pa da ga upisujem u bazu, jer bi to za 300000 slogova bilo isto toliko INSERT INTO komandi, pa sam pokušao da pravim jedan string, nešto ovako:

Code:

$sql = 'INSERT INTO insured (branch, substation, insurance_number, insurance_card, citizen_number, name, surname, insurance_basis) VALUES ';
    
    $xml=simplexml_load_file('KR.xml');
    foreach ($xml->children() as $osiguranik)
    {
        $sql .= '(';
        foreach($osiguranik as $row)
        {
            $sql .= "'$row', ";
        }
        $sql = substr($sql,0,-2) . '), ';
    }  
    $sql = substr($sql,0,-2);
    $db->sql = $sql;
    $db->exec();


Mislim da ovo radi - ne mogu sa sigurnošću da tvrdim jer sam ga pustio pre otprilike 50 minuta i još uvek nije završio. :D

Ima li neko ideju kako ovo može da se odradi brže?
[ Nemke_BG @ 24.10.2012. 11:13 ] @
Poslednje resenje koje si pomenuo je pravo, samo ne preteruj nego napravi na primer 30 inserta koji ubacuju 10 K redova, ili 300 x 1 K, cisto da moze da ti server dise, mozda cak i stavis sleep(5) izmedju iteracija da smanjis load, ako ti nije problem da malo vise sacekas. Ako krenes ovo da radis obavezno pre inserta onemoguci sve indekse, a posle zavrsenog inserta ih vrati, posto mysql reindeksira posle svakog inserta.
[ gotivac @ 24.10.2012. 22:58 ] @
Hvala na odgovoru, ovako sam i uradio, dva sata nakon što sam ovde napisao pitanje.

Pokušao sam sa 10.000 slogova, ali nije išlo jer je dužina sql stringa prelazila default ograničenje od 1MB (može da se promeni u my.ini-ju, ali nisam hteo da preterujem), pa je MySQL server zakucavao, smanjio sam na 5.000 i radi odlično, nema potrebe za sleep-om, jer MySQL taman "odmori" dok PHP izparsuje narednih 5.000. :)
[ kiklop74 @ 25.10.2012. 12:01 ] @
Ako koristis innodb table obavezno raditi import sa transakcijama.