Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [php/xml] Przszpieszenie kodu aktualizacji xml
Forum PHP.pl > Forum > PHP
einter-project
Witam

Napisałem integracje z azymut.pl, niestety sama aktualizacja cen trwa kilka godzin. Czy można jeszcze zoptymalizować kod aby aktualizacja trwała krócej?

Tabela z produktami ma 91 026 rekordów i waży 78,6 MB


Plik xml waży 4,9M i ma 76960 linii.

Struktura pliku:

<?xml version="1.0" encoding="ISO-8859-2"?>

<!DOCTYPE prices SYSTEM "http://services.azymut.pl/oferta/price.dtd">
<prices updated="2011-12-16 17:45:38">
<book indeks="00124700100KV" cena="15.41" vat="23" detal="24.61" />
<book indeks="00130100101KA" cena="10.06" vat="23" detal="16.49" />
<book indeks="00151500101KS" cena="8.25" vat="5" detal="11.55" />
<book indeks="00171000105KS" cena="30.8" vat="5" detal="42.0" />
<book indeks="00195900101KS" cena="9.75" vat="5" detal="13.65" />
<book indeks="00204500101KS" cena="15.0" vat="5" detal="21.0" />
<book indeks="00226800101KS" cena="9.75" vat="5" detal="13.65" />

.........


<book indeks="8DB70601415KS" cena="14.93" vat="5" detal="20.9" />
<book indeks="8DB70701415KS" cena="22.43" vat="5" detal="31.4" />
<book indeks="8DB70801415KS" cena="22.43" vat="5" detal="31.4" />
<book indeks="8DB70901415KS" cena="22.43" vat="5" detal="31.4" />
<book indeks="8DB73101415KS" cena="16.43" vat="5" detal="23.0" />
<book indeks="8DB73201415KS" cena="16.43" vat="5" detal="23.0" />
<book indeks="9PA00301415KS" cena="13.61" vat="5" detal="285.8" />
<book indeks="9PA00401415KS" cena="15.0" vat="5" detal="21.0" />
<book indeks="9PB00101415KS" cena="13.5" vat="5" detal="18.9" />
<book indeks="9PB00201415KS" cena="13.5" vat="5" detal="18.9" />
</prices>

Kod php do obsługi pliku:
  1. <?php
  2. $reader = new XMLReader();
  3. $reader->open('ceny4.xml');
  4.  
  5. $counter = 0;
  6. while($reader->read()) {
  7. if($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'book') {
  8. $indeks = $reader->getAttribute('indeks');
  9. $vat = $reader->getAttribute('vat');
  10. $detal = $reader->getAttribute('detal');
  11. $kplD = $reader->getAttribute('kplD');
  12.  
  13.  
  14.  
  15.  
  16. $mysql->exec("UPDATE `shop_product` SET `product_price_update`=now(), `product_price_netto`='".$detal."', `product_komplet`='".$kplD."', `product_vat`='".$vat."'
  17. WHERE `product_number_catalog_producer`='".$indeks."'");
  18.  
  19. print $indeks.' - '.$vat.' - '.$detal.' - '.$kplD.'<br>';
  20.  
  21. $counter++;
  22. }
  23. }
  24. $reader->close();
  25. ?>


Aktualizacja bazy oparta jest o klasę obsługującą PDO

Bardzo prosiłbym o uwagi.

// Edit
Puściłem aktualizacje o 2011-12-16 18:28:15 i do godziny 2011-12-16 19:23:01 zaktualizował 6 448.
destroyerr
Powinieneś zacząć od pomierzenia czasów, wtedy wiedziałbyś który kawałek kodu opóźnia cały skrypt, tak trzeba gdybać.
Winne mogą być indeksy na tabeli - rozwiązaniem może być ich wyłączenie na czas aktualizacji. Możesz też skorzystać z transakcji i aktualizować rekordy po kilka "w paczce", coś jak tutaj. W chwili obecnej aktualizujesz wszystkie rekordy, nawet te które się nie zmieniły.
Ostatnia możliwość, to przygotowanie pliku sql i wrzucenie go do bazy (np. przez konsolę).
einter-project
Pobawiłem się trochę skryptem i na pewno to wina PDO że tak wolno działa.

Mam teraz do was pytanie które zapytanie będzie bardziej wydajne, najmniej obciąży serwer i które byście zastosowali na takiej dużej bazie:
Opcja 1
  1. <?php
  2.  
  3. $reader = new XMLReader();
  4. $reader->open('ceny4.xml');
  5.  
  6.  
  7.  
  8. $connection = @mysql_connect(DB_SERVER, DB_SERVER_USERNAME, DB_SERVER_PASSWORD)
  9. // w przypadku niepowodznie wyświetlamy komunikat
  10. or die('Brak połączenia z serwerem MySQL.<br />Błąd: '.mysql_error());
  11.  
  12. // nawiązujemy połączenie z bazą danych
  13. $db = @mysql_select_db(DB_DATABASE, $connection)
  14. // w przypadku niepowodzenia wyświetlamy komunikat
  15. or die('Nie mogę połączyć się z bazą danych<br />Błąd: '.mysql_error());
  16.  
  17. $counter = 0;
  18. while($reader->read()) {
  19. if($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'book') {
  20. $indeks = $reader->getAttribute('indeks');
  21. $vat = $reader->getAttribute('vat');
  22. $detal = $reader->getAttribute('detal');
  23. $kplD = $reader->getAttribute('kplD');
  24.  
  25.  
  26. mysql_query("UPDATE `shop_product` SET `product_price_update`=now(), `product_price_netto`='".$detal."', `product_komplet`='".$kplD."', `product_vat`='".$vat."'
  27. WHERE `product_number_catalog_producer`='".$indeks."'");
  28.  
  29. print $counter.' - '.$indeks.' - '.$vat.' - '.$detal.' - '.$kplD.'<br>';
  30.  
  31. $counter++;
  32. }
  33. }
  34. $reader->close();
  35.  
  36. mysql_close($connection);
  37.  
  38. ?>



Opcja 2
  1.  
  2. $reader = new XMLReader();
  3. $reader->open('ceny4.xml');
  4.  
  5. $counter = 0;
  6. while($reader->read()) {
  7. if($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'book') {
  8. $indeks = $reader->getAttribute('indeks');
  9. $vat = $reader->getAttribute('vat');
  10. $detal = $reader->getAttribute('detal');
  11. $kplD = $reader->getAttribute('kplD');
  12.  
  13. $connection = @mysql_connect(DB_SERVER, DB_SERVER_USERNAME, DB_SERVER_PASSWORD)
  14. // w przypadku niepowodznie wyświetlamy komunikat
  15. or die('Brak połączenia z serwerem MySQL.<br />Błąd: '.mysql_error());
  16.  
  17. // nawiązujemy połączenie z bazą danych
  18. $db = @mysql_select_db(DB_DATABASE, $connection)
  19. // w przypadku niepowodzenia wyświetlamy komunikat
  20. or die('Nie mogę połączyć się z bazą danych<br />Błąd: '.mysql_error());
  21.  
  22. mysql_query("UPDATE `shop_product` SET `product_price_update`=now(), `product_price_netto`='".$detal."', `product_komplet`='".$kplD."', `product_vat`='".$vat."'
  23. WHERE `product_number_catalog_producer`='".$indeks."'");
  24.  
  25. mysql_close($connection);
  26.  
  27. print $counter.' - '.$indeks.' - '.$vat.' - '.$detal.' - '.$kplD.'<br>';
  28.  
  29. $counter++;
  30. }
  31. }
  32. $reader->close();
Crozin
1. Jak już @destroyerr zauważył obejmij całość transakcją albo wyłącz indeksowanie na czas aktualizacji - w chwili obenej niepotrzebnie każdorazowo przebudowywany jest indeks.
2. Użyj PDO i prepared statements - nie ma potrzeby w kółko "przesyłać całego zapytania".
einter-project
Witam

Powróciłem dzisiaj do tematu:
Od Crozina dostałem taki oto kodzik:

  1. $pdo = new PDO('mysql:host='.DB_SERVER.';dbname='.DB_DATABASE, DB_SERVER_USERNAME, DB_SERVER_PASSWORD, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES ".$conf->MyCharset));
  2. $pdo->beginTransaction();
  3. $stmt = $pdo->prepareStatement('UPDATE `shop_product` SET `product_price_update`=now(),
  4. `product_price_netto` = :price,
  5. `product_komplet` = :komplet,
  6. `product_vat` = :vat
  7. WHERE `product_number_catalog_producer` = :key');
  8.  
  9.  


I wyskakuje mi taki błąd:
Call to undefined method PDO::prepareStatement()

Czy można prosić o pomoc czy nazwa funkcji PDO jest prawidłowa?

Pozdrawiam


einter-project
Dzięki nospor ale czytałem, z tym że od Crozina dostałem taki oto kodzik:
  1. <php
  2. $pdo = new PDO(...);
  3.  
  4. $pdo->beginTransaction();
  5. $stmt = $pdo->prepareStatement('UPDATE ... SET ..., price = :price, vat = :vat ... WHERE key = :key');
  6.  
  7. while (...) {
  8. ...
  9.  
  10. $stmt->execute(array(
  11. 'price' => $price,
  12. ...
  13. 'key' => $key
  14. ));
  15. }
  16.  
  17. $pdo->commit();
  18. ?>
  19.  



Napisałem:
  1. <?php
  2. // Pobranie informacji o ostatniej aktualizacji cen
  3. $DB->update = $mysql->recordOne("SELECT * FROM `".DB_PREFIX."azymut` WHERE `azymut_action`='update_price';");
  4.  
  5. $pdo = new PDO('mysql:host='.DB_SERVER.';dbname='.DB_DATABASE, DB_SERVER_USERNAME, DB_SERVER_PASSWORD, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES ".$conf->MyCharset));
  6. $pdo->beginTransaction();
  7. $stmt = $pdo->prepareStatement('UPDATE `shop_product` SET `product_price_update`=now(),
  8. `product_price_netto` = :price,
  9. `product_komplet` = :komplet,
  10. `product_vat` = :vat
  11. WHERE `product_number_catalog_producer` = :key');
  12.  
  13. $reader = new XMLReader();
  14. $reader->open('../mysql/ceny4.xml');
  15.  
  16. $counter = 0;
  17. while($reader->read()) {
  18. if($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'book') {
  19. $indeks = $reader->getAttribute('indeks');
  20. $vat = $reader->getAttribute('vat');
  21. $detal = $reader->getAttribute('detal');
  22. $kplD = $reader->getAttribute('kplD');
  23.  
  24. $stmt->execute(array(
  25. 'price' => $detal,
  26. 'komplet' => $kplD,
  27. 'vat' => $vat,
  28. 'key' => $indeks));
  29. }
  30. }
  31. $pdo->commit();
  32. ?>


Wydaje mi się że dobrze napiałem, według jego przykładu. Ewentualnie jeśli byś mógł napisać co jest nie tak, a nie linkować to byłbym wdzięczny.
Pozdrawiam
nospor
1) Nie widzę w tym temacie, byś od crozina dostawał jakikolwiek kod.
2) prepareStatement() - nie ma takiej funkcji

1+2 = ktoś tutaj klamie

Podałem ci linka do manuala, z którego jasno wynika że jest funkcja prepare(). Zamiast się więc upierać przy prepareStatement() to posłuchaj co ci mówi komunikat błędu połącz to zlinkiem co ci dałem i zrób prostą poprawkę.
einter-project
Nie rozumiem po co piszesz jak nie chcesz pomóc.
1) dostałem na pw, istnieje coś takiego na tym forum
2) wiem że nie ma takiej funkcji, dlatego piszę co jest nie tak

Chyba sobie poradziłem więc dzięki za wysiłek.
nospor
Cytat
Nie rozumiem po co piszesz jak nie chcesz pomóc.
Dałem ci linka do rozwiązania. Nie moja wina, że nie umiesz połączyć dwóch prostych faktów ze sobą wiec nie pisz, że nie chcę pomoc.

Cytat
wiem że nie ma takiej funkcji, dlatego piszę co jest nie tak
Dlatego podałem ci linka, który wyjaśnia co jest nie tak :/

edit: a z tym kłamaniem to nie napisałem o kogo mi chodzi tongue.gif Równie dobrze mogło mi chodzić o to, że crozin kłamał podając ci złą nazwę funkcji - choć w tym przypadku można raczej mówić o zwykłej pomyłce
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.