Dag allemaal,

ik maak gebruik van een cronjob on elke 2 uur een bestand te downloaden (csv, of zip)
dit bestand wordt uitgepakt indien nodig, en dan het csv bestand in stukken gehakt (indien nodig)
vervolgens importeer ik de csv op basis van mijn eigen database.

de import bevat voor elke regel een SELECT en indien er een resultaat is, enkele simpele berekeningen en een UPDATE achteraan.

Nou heb ik het probleem dat elke 2 uur m'n CPU omhoog vliegt en ook ALLE geheugen waardoor er op dat moment t/m 5 minuten ofzo vrijwel geen verkeer mogelijk is.
Op dat moment kan ik nieteens met ssh inloggen.
Als ik wel ingelogt ben kan ik op dat moment nieteens 'top' uitvoeren (linux server) dat er geen geheugen beschikbaar is.

Dus mijn vraag is eigenlijk:
-hoe weet ik hoeveel geheugen die cronjobs gebruiken
-hoe kan ik een memory limit geven

ik heb een simpele VPS 2x duo core cpu's en 4GB geheugen
Ik ben bang dat het niet veel uitmaak dat ik upgrade naar 4 CPU en 8GB geheugen?

Ik hoor graag van jullie!
Ik zou eerder kijken waarom er veel geheugen wordt gebruikt. Kijk eens naar memory_get_peak_usage()
Ho Arien

thanks, maar.. op welke momenten moet ik dit doen dan?
Aan het begin, halverwege aan het einde?
Het script geeft geen output, en ik draai t dmv nohup
Ik kan het 'loggen'

Ik zit te denken om t te loggen met timestamps naar een file
begin, voor en na download, voor/na uitpak, einde

zou ik ook bij elke regel moeten loggen?

het gaat in principe maar om een csv bestand van max. 16mb
want ik hak ze in stukken ook.

kan ik niet gewoon een max. memory geven, alleen dan is de vraag hoe bepaal ik het limiet het beste
Je kan de memorywaarde prima loggen in een txt-file. Als er veel geheugen wordt gebruikt denk ik vaak aan een infinite loop.
Hi Arien,

ik zal eens een beetje gaan loggen. Per script een eigen file en daarna kan ik hier snel ff een grafiek oid van maken :)


Ik had daarnet wel weer een piek, maar dat bleek CPU te zijn op een process van mysql
"/usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir............"
Alleen zegt het verder ook niet veel

De CPU voor dit process sprong van 45 seconden naar 120%

Maar ik wil dit zsm goed oplossen omdat ik in toekomst nog meer van dit soort imports zal gaan draaien..

Er is geen 'oneindige' loop in m'n cron scripts.. Dat weet ik 100% zeker, maar sommige kunnen wat langer draaien dan andere, door o.a. downloaden van grote csv of zip file, het 'splitten' van de file(s) om sneller te kunnen verwerken enz.
Ga daarom per onderdeel de performance loggen.
misschien is een andere benadering handiger:

Mysql kan prima met LOAD DATE INFILE een csv bestand inlezen.
Kun je in een tijdelijke tabel pompen.

En daarna zou ik 1x query doen die met een join tussen de doeltabel en de tijdelijke tabel de zaak update.

Klink nu namelijk of je 1000 SELECT query's afvuurt en een berg updates. Waarbij je mogelijk steeds meer PHP variabelen aanmaakt om je geheugen te vullen.

Dan lijken 2 query's me efficiënter
Dat, en een borkend mysql proces geeft ook te denken over de efficientie van je queries, indexes, en mogelijk je mysql configuratie. Kijk hier dus ook zeker naar.
Goede morgen allen,

ik ga nu memory logs invoeren en dan weet ik rond 8:30 wellicht iets meer.
Om meer toelichting te geven @Ivo en Ben over de import.

ik heb verschillende csv files, met daarbij allemaal hun eigen kolommen
Een oplossing daarvoor had ik als volgt: een 'settings' file voor de import waarbij ik het volgende gedefineerd heb:

$settings = array('import_file' => 'local_path_to_the_csv_file',
'import_colomn_0_to => mijn_database_kolom',
import_colomn_1_to => mijn_database_kolom2',
import_colomn_2_to => '',
import_colomn_3_to => '',
'import_colomn_4_to' => 'mijn_database_kolom3',
...
...
'import_colomn_31_to' => 'mijn_database_kolom4',
'import_uniqueField' => 'mijn_database_kolom_3');


Hierna volgt vanuit PHP nogmaals een nohup commando dat m'n import script triggered.

Voor elke regel in de csv file, controlleer ik of ik wel alle data heb (op basis van de 'settings' file) die ik nodig heb (het kan weleens wezen dat de csv geen goede opmaak heeft en niet alle kolommen mee komen.
Daarna normaliseer ik de waardes zoals bedragen, voorraad enz

Daarna doe ik een SELECT op import_uniqueField
als er een result is, doe ik deze updaten.

En aan het einde altijd een die(); gewoon voor het geval dat.

@Ivo,
aangezien de CSV files allemaal anders zijn, zou ik deze 'tijdelijke' tabel eerst kunnen creeren (dynamisch of 1 standaard grote tabel maken, met dezelfde veldnamen als m'n settings file, maar dan ... t/m import_colomn_100_to (als voorbeeld)) en dan alles erin zetten
Zou dat inderdaad beter zijn?

vervolgens 1 lange SELECT dmv JOIN om de relatie te leggen tussen import_uniqueField?
Ik moet alsnog alle updates 1 voor 1 doen, omdat voorraad en prijzen nogal wat berekeningen nodig heeft, dus houd ik altijd nog duizenden update queries, + uiteraard maar 1 grote SELECT query

Wellicht een goed idee
Dit is alsnog wel per import file, omdat ze allen anders zijn. En andere 'settings' hebben.


@Ben, de queries zijn simpel: SELECT field_id FROM table WHERE field_id = $cvsRow[$settings['import_uniqueField']]

Aan wat voor configuratie zat je te denken eigenlijk? Ik heb geen aparte configuratie toegepast op de mysql service.
"Daarna doe ik een SELECT op import_uniqueField
als er een result is, doe ik deze updaten."

Dus als uniqueField = "abc123" niet bestaat, doe je niets en anders doe je een update query?

Dat is dus gelijk aan
UPDATE tabel SET .... WHERE uniqueField="abc123"

als die niet gevonden is, doet zo'n query namelijk precies niets.

[size=xsmall]Toevoeging op 06/03/2017 09:08:34:[/size]

LOAD DATA INFILE kan heel snel een tabel vullen. Met alle kolommen 1 op 1 matchend, of alleen kolom 1, 5 en 23 uit je file.
Je kunt er zelfs nog een bewerking op doen op het moment van importeren:

LOAD DATA INFILE 'file.txt'
INTO TABLE t1
(column1, @var1)
SET column2 = @var1/100;

Maar ook opties als
LOAD DATA INFILE 'file.txt'
INTO TABLE t1
(column1, column2)
SET column3 = CURRENT_TIMESTAMP;

of
LOAD DATA INFILE 'file.txt'
INTO TABLE t1
(column1, @dummy, column2, @dummy, column3);

waarbij dan dus kolom 2 en 4 uit file.txt eigenlijk gewoon overgeslagen worden.

En wat voor soort berekeingen heb je nodig die zo moeilijk zijn mbt de prijs?
Je vergelijkt data in een nieuwe CSV met data in je database, maar je zou er nog een vergelijking aan vooraf kunnen laten gaan. Als je namelijk elke 2 uur een CSV downloadt, is er een grote kans dat zo'n 50 tot misschien wel meer dan 80 procent van dat CSV-bestand identiek is aan het CSV-bestand dat je 2 uur eerder al verwerkt hebt. Kortom: je hoeft alleen de diff met nieuwe of gewijzigde data te verwerken, want de rest heb/weet je al.

Aangezien fgetcsv() een array retourneert, zou je het verschil tussen twee CSV-bestanden bijvoorbeeld kunnen vinden met array_diff().

Bijkomend voordeel is dat je dan ook nog het opschonen van de CSV-bestanden kunt beperken tot de nieuwe of gewijzigde data als je eerst alle overeenkomsten tussen de oorspronkelijke CSV's weggooit.

Reageren