Grosse Datenmenge mit SELECT, Artikel über SW API erstellen

Guten Tag,

  • Ich habe ein eigenes Datenmodell und eine dazugehörige MySQL Tabelle erstellt (h_Article).
  • Diese Daten sollen über den SELECT Query später noch gefiltert werden und per Shopware Article API Manager gespeichert werden.

 

Das funktioniert soweit, aber die Aktion bricht nach ca. 2500 gespeicherten Artikeln ab (insgesamt ca. 240’000). Womöglich weil das Memory vollgelaufen ist. Eher kein Timeout, da der Task ca. >10 Minuten gelaufen ist.

 

 $resource = new Client(); $sql = "SELECT \* from h\_Article"; $result = Shopware()-\>Db()-\>query($sql); foreach ($result as $article) { $resource-\>addArticleInformation($article); } 

 

Der Methode addArticleInformation werden die einzelnen Artikel aus dem SQL Result übergeben und von da aus werden diese über die SW API gespeichert.
 

Wie kann der Code optimiert werden, dass beispielsweise Zeile für Zeile selektiert und importiert wird, um das Memory zu schonen?

 

 

EDIT: Soeben habe ich gerade folgende Errormessage erhalten, es scheint also defintiiv das Memory-Limit zu sein.

Fatal error : Allowed memory size of 134217728 bytes exhausted (tried to allocate 4536001 bytes) in  C:\htdocs\incocare.ch\engine\Shopware\Components\Thumbnail\Generator\Basic.php  on line  221

Ich würde das über Pages Queries lösen und die Daten „Chunkweise“ rüber schaufeln.

1 „Gefällt mir“

Besten Dank für den Tipp. Ich habe bereits an die Pagination direkt im SQL Query gedacht. Diese habe ich jetzt mal implementiert:

 

 $limit = 20; $offset = 0; for ($i = 0; $i \< 240000000; $i++) { $sql = "SELECT hci\_article.pharmacode, hci\_article.dscrpackd, hci\_article.dt, hci\_article.dscrpackf, hci\_article.dscrd, hci\_article.gtin, hci\_article.artpri\_exf, hci\_article.artpri\_pub, hci\_article.vat, hci\_article.weight, hci\_article.img2, hci\_company.nams, hci\_company.prtno, hci\_product.smcat, hci\_kompendium\_product.monid, hci\_compendium.content, hci\_product.prdno, hci\_product.bnamd, hci\_article.width, hci\_article.height, hci\_article.depth, hci\_product.smcat, hci\_article.qtyud, hci\_article.salecd FROM hci\_article LEFT JOIN hci\_company ON hci\_article.artcomp\_h = hci\_company.prtno LEFT JOIN hci\_product ON hci\_article.prdno = hci\_product.prdno LEFT JOIN hci\_kompendium\_product ON hci\_product.prdno = hci\_kompendium\_product.prdno LEFT JOIN hci\_compendium ON hci\_compendium.monid = hci\_kompendium\_product.monid WHERE 1=1 AND hci\_product.del = FALSE AND hci\_article.salecd='N' AND (hci\_product.smcat='C' OR hci\_product.smcat='D' OR hci\_product.smcat='E') AND hci\_compendium.monidlang LIKE '%DE' LIMIT " . $limit . " OFFSET " . $offset; $result = Shopware()-\>Db()-\>query($sql); foreach ($result as $article) { $resource-\>addArticleInformation($article); } $offset = $offset + 20; $pluginLogger-\>info('Batch ' . $offset . ' - erfolgreich importiert.'); }

 

Leider bricht der Import bei jeweils ca. 2500 Artikeln ab, ich kann aber nicht nachvollziehen warum das passiert.

@hagmann.io schrieb:

Besten Dank für den Tipp. Ich habe bereits an die Pagination direkt im SQL Query gedacht. Diese habe ich jetzt mal implementiert:

 

$limit = 20; $offset = 0; for ($i = 0; $i < 240000000; $i++) { $sql = "SELECT hci_article.pharmacode, hci_article.dscrpackd, hci_article.dt, hci_article.dscrpackf, hci_article.dscrd, hci_article.gtin, hci_article.artpri_exf, hci_article.artpri_pub, hci_article.vat, hci_article.weight, hci_article.img2, hci_company.nams, hci_company.prtno, hci_product.smcat, hci_kompendium_product.monid, hci_compendium.content, hci_product.prdno, hci_product.bnamd, hci_article.width, hci_article.height, hci_article.depth, hci_product.smcat, hci_article.qtyud, hci_article.salecd FROM hci_article LEFT JOIN hci_company ON hci_article.artcomp_h = hci_company.prtno LEFT JOIN hci_product ON hci_article.prdno = hci_product.prdno LEFT JOIN hci_kompendium_product ON hci_product.prdno = hci_kompendium_product.prdno LEFT JOIN hci_compendium ON hci_compendium.monid = hci_kompendium_product.monid WHERE 1=1 AND hci_product.del = FALSE AND hci_article.salecd=‚N‘ AND (hci_product.smcat=‚C‘ OR hci_product.smcat=‚D‘ OR hci_product.smcat=‚E‘) AND hci_compendium.monidlang LIKE ‚%DE‘ LIMIT " . $limit . " OFFSET " . $offset; $result = Shopware()->Db()->query($sql); foreach ($result as $article) { $resource->addArticleInformation($article); } $offset = $offset + 20; $pluginLogger->info(‚Batch ’ . $offset . ’ - erfolgreich importiert.‘); }

 

Leider bricht der Import bei jeweils ca. 2500 Artikeln ab, ich kann aber nicht nachvollziehen warum das passiert.

Ja klar, weil Deine for Schleife auch nicht besser ist. Was Du suchst / brauchst ist das Iterator-Verfahren. Und dieses erreichst Du entweder über eine foreach Schleife, oder mit der sogenannten PDO Cursor fetch Methode.

Bei ein for Schleife fängt er jedes mal wieder bei Array Index 0 das Suchen an, während er beim Iterator Verfahren einfach vom letzten auf den nächsten Array Index springt (wie bei fopen und fgets bei einer simplen Textdatei). Das ist gerade bei großen Datenmengen interessant, also eben in Deinem Fall.

Hol dir am besten über den DBAL Service (Shopware Container) das PDO Objekt und führe Deinen Query mittels PDO Cursor fetch Zeile für Zeile aus. Siehe dazu am besten Beispiel #2 in der PHP Doku, besser hätte ich es auch nicht erklären können. Den Code kannst du 1:1 so übernehmen (davor kommt logischweise noch der Service Abruf für das PDO Objekt): PHP: PDOStatement::fetch - Manual