ugrás a tartalomhoz

Egyik adatbázisból a másikba másolás bizonyos feltételek teljesülése esetén

kotapeter · 2014. Okt. 1. (Sze), 19.00
Sziasztok!

Egy webáruházat fejlesztek és azt szeretném megoldani, hogy az offline bolt raktárkészletét folyamatosan kövesse a webáruház raktárkészlete. Kb. 3000 termékről van szó.
Tehát ha eladnak valamit az offline boltban, akkor a webáruházban is csökkenjen annak a terméknek a darabszáma.

Ezt egyelőre egy cron-al oldottam meg. Linkelem a PHP kódot, ami minden egyes percben lefutott.
  1. <?php  
  2.     $db = new MySQLi(offline üzlet adatbázisa);  
  3.     $db2 = new MySQLi(online üzlet adatbázisa);  
  4.   
  5.     if ($db->connect_errno) {  
  6.         exit();  
  7.     }  
  8.       
  9.     $lekerdez = "select cikkszam,cikkszam_nev,db,kisker_ar,nyilv_ar,kategoria,db from cikkszam order by 1";  
  10.     $lekerdez2 = "select model,quantity from bio_product";  
  11.   
  12.     $talalat = $db->query($lekerdez);  
  13.     $talalat2 = $db2->query($lekerdez2);   
  14.       
  15.     $n = $talalat->num_rows;  
  16.     $s = $talalat2->num_rows;  
  17.   
  18.     for ($i=0; $i<$s$i++) {  
  19.   
  20.         $sor2 = $talalat2->fetch_assoc();  
  21.         $aktdb=0;  
  22.         for ($j=0; $j<$n$j++) {  
  23.             $sor = $talalat->fetch_assoc();  
  24.             if (stripslashes($sor['cikkszam']) == stripslashes($sor2['model']) && stripslashes($sor['db']) != stripslashes($sor2['quantity'])) {  
  25.                 $aktdb = $sor['db'];  
  26.                 mysqli_query($db2,"UPDATE bio_product SET quantity=".$aktdb." WHERE model='".stripslashes($sor2['model'])."'");  
  27.                 break;  
  28.             }  
  29.         }  
  30.         $talalat = $db->query($lekerdez);  
  31.     }  
  32.     $db->close();  
  33. ?>  
Nos, ezzel az egyszerű kóddal az a legnagyobb gond, hogy 3000 termék esetén csekély 4 óra alatt fut le.
Biztos vagyok benne, hogy van ennél sokkal jobb és elegánsabb megoldás.

Ha van ötletetek kérlek osszátok meg velem!

Köszönöm!

Peti
 
1

Eseményvezérlés

Pepita · 2014. Okt. 1. (Sze), 19.10
Nem kellene összevont ciklus, hanem valamilyen eseményvezérlés, amit az offline készletező indít, ha eladás (vagy beszerzés) történik. Pl. egy külön táblába felveszi a módosított termék cikkszámát.
A crontabod így már csak ebből a táblából "válogatva" keres - néhány ms alatt és természetesen törli / frissíti ebben a táblában is a feldolgozott rekordokat.
2

Adatbázis optimalizálás

tisch.david · 2014. Okt. 1. (Sze), 21.24
Kedves Péter!

- Muszáj két külön adatbázisban lennie a két rendszernek? Egyszerűbb lenne, ha mindenki ugyanazzal a raktárkészlettel gazdálkodna.
- Ez a kód, amit írtál, csak a webshop adatbázisát igazítja az offline boltéhoz, fordítva nem frissít. Mi van, ha a webshopban adnak el? Akkor nem kéne a bolti készletet is csökkenteni? Másrészt a frissítésben a mennyiségeknél a != operátort használod. Az nem gond, ha a webshop kevesebb készletét csapod agyon a boltban nyilvántartott nagyobb értékkel?
- Ha mindenképpen ezt az utat akarod járni, akkor nem tudod megoldani, hogy a webshop adatbázisából elérhető legyen a másik adatbázis? Mert akkor sokkal hatékonyabb SQL utasítással nagyon rövid idő alatt is frissíthetnéd az online készletet.

Üdv:

Dávid
3

optimalizáció

szabo.b.gabor · 2014. Okt. 2. (Cs), 08.53
==================================
A meglévő kódot így optimalizálnám
==================================

---------------
Sztem strip_slashes felesleges db -> db adatmozgásnál, feltételezve hogy a cikkszám nem tartalmaz veszélyes karaktereket. Sztem ez teljesül, de ez a pont nem is fontos.

---------------
Két ciklusod van, mind a kettő 3000 sort tartalmaz 3000*3000 az 9 000 000 iteráció, ráadásul a $db-n 3000-szer kéred le ugyanazt :D

Szóval rendezd mind a két lekérdezésedet cikkszám szerint, és hol az egyik hol a másik rekordset-en hívd a fetch-t aszerint, hogy melyik tartalmaz kisebb értéket, ha egyezés van, akkor hajtsd végre a vizsgálatot, módosítást.

Ezt a pontot csináld, meg ettől lesz gyorsabb a történet.

---------------
Valamint csinálhatsz még prepared statementet az update-re, de amíg csak 10-20 update van, addig ezzel sem fogsz sokat nyerni.

---------------
Ja meg for ciklusok helyett inkább while(($row = $talalat->fetch()) !== false){}

====================

Amúgy érdemes volna elgondolkodni olyasmin amit Pepita mondott, esetleg valami queue-t létrehozni, amibe beledobálod a változásokat, a másik oldalon meg tárolod, hogy meddig vannak feldolgozva a változások. Ami ezt a queue-t tölti, az feltöltés után akár meg is hívhatná a másik oldal feldolgozó script-jét.

Arra is figyelned kellene, hogy ezek a script-ek ne fussanak egymásra, db lockokkal vagy akár azt biztosítani, hogy csak egy példány futhasson a feldolgozó scriptből.
4

Plusz

Hidvégi Gábor · 2014. Okt. 2. (Cs), 10.55
Talán ilyenkor legcélszerűbb egy fájlba kiírni az egészet, azon belül is egy tranzakcióba.

frissit.sql tartalma:

BEGIN;

UPDATE bio_product SET quantity=5 WHERE model=2200;
UPDATE bio_product SET quantity=0 WHERE model=3410;

COMMIT;

Aztán a végén egy parancsot kell lefuttatni:
exec('mysql -u user -p jelszo sema_neve < frissit.sql', $kimenet_tomb, $visszateresi_ertek);

Ha háromezer terméket kell frissíteni, annak elvileg pár másodperc alatt meg kell így lennie. A 'sema_neve' az "adatbázis", amiben a bio_product tábla van.

Emellett szerintem a php szintjén nem feltétlenül érdemes vizsgálni, hogy változott-e a termékek darabszáma, ugyanis az UPDATE esetén a MySQL ezt megteszi. Ha nem változik az érték, akkor azt a frissítő lekérdezést egyszerűen nem futtatja le, és elképzelhetőnek tartom, hogy ha a nyers erő módszerével egyszerűen minden sorra írnál UPDATE-et, az is gyorsítana (3000 soron egy-egy műveletet elvégezni az nem tétel az adatbáziskezelőnek).
5

DB export/import

gabesz666 · 2014. Okt. 3. (P), 09.31
Bár jóval szebb megoldást is tudnék mondani, de mint legegyszerűbb és az általad írt megoldásnál valószínűleg jóval gyorsabb eredményt lehetne elérni, ha csinálsz egy mysql dump-ot a forrás adatbázisról, dobod a cél adatbázist és beimportálod a dump-ot. Persze ez csak akkor működik, ha a két adatbázis struktúrája egy az egyben megegyezik.
6

Profibb

janoszen · 2014. Okt. 3. (P), 12.06
Ennel vannak sokkal professzionalisabb megoldasok, ugy hivjak oket, hogy ETL toolok. Ezek olyan eszkozok, amiket a BI (Business Intelligence) szektorban hasznalnak es nagy mennyisegu adatbetoltesre szolgalnak.

Ha tudsz a szerveren Java-t futtatni, nezd meg a Kettle-t, valoszinuleg sokkal jobban fog mukodni mint a kezzel irt megoldasok.
7

Kimaradt

Pepita · 2014. Okt. 3. (P), 17.05
Elsőre kifelejtettem a kétirányúságot, ami szintén fontos.
Azt is kezelned kell, ha a webshop adott el vmit.
Az is jó ötlet, hogy egy db legyen, ha lehet.

A dump mindezt kinyírja, semmiképp sem jó.
8

slave

Poetro · 2014. Okt. 3. (P), 17.26
Vagy ha nem is egy db, de legyen legalabb slave.
9

hogy?

Pepita · 2014. Okt. 3. (P), 22.39
A slave hogyan tud visszahatni a master keszletere?
10

Másolás

Poetro · 2014. Okt. 3. (P), 22.41
Az offline raktárkészletet a slave-be kellene replikálni, és akkor könnyebb lenne hozzáférni, mert egy gépen futna a kettő.