Top-Themen

AppleEntwicklungHardwareInternetLinuxMicrosoftMultimediaNetzwerkeOff TopicSicherheitSonstige SystemeVirtualisierungWeiterbildungZusammenarbeit

Aktuelle Themen

Administrator.de FeedbackApache ServerAppleAssemblerAudioAusbildungAuslandBackupBasicBatch & ShellBenchmarksBibliotheken & ToolkitsBlogsCloud-DiensteClusterCMSCPU, RAM, MainboardsCSSC und C++DatenbankenDatenschutzDebianDigitiales FernsehenDNSDrucker und ScannerDSL, VDSLE-BooksE-BusinessE-MailEntwicklungErkennung und -AbwehrExchange ServerFestplatten, SSD, RaidFirewallFlatratesGoogle AndroidGrafikGrafikkarten & MonitoreGroupwareHardwareHosting & HousingHTMLHumor (lol)Hyper-VIconsIDE & EditorenInformationsdiensteInstallationInstant MessagingInternetInternet DomäneniOSISDN & AnaloganschlüsseiTunesJavaJavaScriptKiXtartKVMLAN, WAN, WirelessLinuxLinux DesktopLinux NetzwerkLinux ToolsLinux UserverwaltungLizenzierungMac OS XMicrosoftMicrosoft OfficeMikroTik RouterOSMonitoringMultimediaMultimedia & ZubehörNetzwerkeNetzwerkgrundlagenNetzwerkmanagementNetzwerkprotokolleNotebook & ZubehörNovell NetwareOff TopicOpenOffice, LibreOfficeOutlook & MailPapierkorbPascal und DelphiPeripheriegerätePerlPHPPythonRechtliche FragenRedHat, CentOS, FedoraRouter & RoutingSambaSAN, NAS, DASSchriftartenSchulung & TrainingSEOServerServer-HardwareSicherheitSicherheits-ToolsSicherheitsgrundlagenSolarisSonstige SystemeSoziale NetzwerkeSpeicherkartenStudentenjobs & PraktikumSuche ProjektpartnerSuseSwitche und HubsTipps & TricksTK-Netze & GeräteUbuntuUMTS, EDGE & GPRSUtilitiesVB for ApplicationsVerschlüsselung & ZertifikateVideo & StreamingViren und TrojanerVirtualisierungVisual StudioVmwareVoice over IPWebbrowserWebentwicklungWeiterbildungWindows 7Windows 8Windows 10Windows InstallationWindows MobileWindows NetzwerkWindows ServerWindows SystemdateienWindows ToolsWindows UpdateWindows UserverwaltungWindows VistaWindows XPXenserverXMLZusammenarbeit

While Schleife - Zu bestimmter Stelle springen

Frage Entwicklung PHP

Mitglied: ottscho

ottscho (Level 2) - Jetzt verbinden

08.03.2013 um 08:09 Uhr, 2902 Aufrufe, 15 Kommentare, 1 Danke

Moin,

ich habe ein Import, mit welcher ich 100t Datensätze aus einer CSV in eine DB importiere.
Das Ganze läuft über ein Script, welches sich wegen Servertimeout immer wieder selbst aufruft.
Es gibt ein Step Wert und ein Offset Wert.

Step=500
Offset0

D.h. Gestartet wird mit dem Datensatz 0 und es werden 500 abgearbeitet. Dann wird das Script erneut aufgerufen mit dem Step=500 und dem Offset= 500.
Jetzt werden die ersten 500 Datensätze übersprungen und dann geht es ab 500 weiter mit dem Import. usw.


01.
$row = 1; // Anzahl der Arrays 
02.
			$handle = fopen ("upload/artikel.csv","r"); // Datei zum Lesen �ffnen 
03.
			// Die erste Zeile mit den Spaltennamen auslesen 
04.
			$data = fgetcsv ($handle, 100000, ";"); 
05.
			if(is_array($data)) { 
06.
			   foreach($data AS $cellNr => $cellName) { 
07.
				   $cellNamesArray[$cellNr] = $cellName
08.
09.
10.
			$return=false;		 
11.
			while ( ($data = fgetcsv ($handle, 100000, ";")) !== FALSE ) { // Daten werden aus der Datei 
12.
				$num = count ($data); // Felder im Array $data 
13.
				//var_dump('row: '.$row); 
14.
				//var_dump('offset: '.$offset); 
15.
				//var_dump('step: '.$step); 
16.
				 
17.
				if ($row <= $offset) { 
18.
					$row++; // Anzahl der Arrays wird 
19.
					continue
20.
21.
				if ($row > $offset+$step) { 
22.
					$return=true; 
23.
					break
24.
25.
				$row++; // Anzahl der Arrays wird 
26.
				$count = 0; 
27.
				for ($c=0; $c < $num; $c++) { // FOR-Schleife, um Felder des Arrays auszugeben 
28.
					$feld[$cellNamesArray[$c]] = $data[$c]; 
29.
					$count++;	 
30.
31.
				 
32.
				//**********************// 
33.
				//*** IMPORT Routine ***// 
34.
				//**********************// 
35.
 
36.
37.
                                



Jetzt meine Frage. Je länge, das Script läuft, um so langsamer wird es bei den letzte Datensätzen. Da ja z.B bei dem Offset 50000, davor in der Schleife erst mal 49999 übersprungen werden, bis dann ab 50000 die nächsten 500 importiert werden.

Es muss doch möglich sein, direkt den Einstiegspunkt mitzugeben. So dass nicht erst die bereits importierten Datensätze übersprungen werden müssen.

ich hoffe ihr versteht wie ich das meine ;)

Besten Dank

Gruß ottscho



Mitglied: flow.ryan
08.03.2013 um 08:50 Uhr
Zitat von ottscho:
Moin

Hallo


ich habe ein Import, mit welcher ich 100t Datensätze aus einer CSV in eine DB importiere.
Das Ganze läuft über ein Script, welches sich wegen Servertimeout immer wieder selbst aufruft.
Es gibt ein Step Wert und ein Offset Wert.

Step=500
Offset0

D.h. Gestartet wird mit dem Datensatz 0 und es werden 500 abgearbeitet. Dann wird das Script erneut aufgerufen mit dem Step=500
und dem Offset= 500.
Jetzt werden die ersten 500 Datensätze übersprungen und dann geht es ab 500 weiter mit dem Import. usw.

Idee ist okay.. aber:


Jetzt meine Frage. Je länge, das Script läuft, um so langsamer wird es bei den letzte Datensätzen. Da ja z.B bei
dem Offset 50000, davor in der Schleife erst mal 49999 übersprungen werden, bis dann ab 50000 die nächsten 500
importiert werden.


Und hier hast du den Grund dafür. Das Teil muss ja so jedes Mal alle vorherigen Datensätze "überspringen".

01.
 				if ($row <= $offset) { 
02.
 					$row++; // Anzahl der Arrays wird 
03.
 					continue
04.
05.
 				if ($row > $offset+$step) { 
06.
 					$return=true; 
07.
 					break
08.
09.
 				$row++; // Anzahl der Arrays wird
Du hättest jetzt folgende Möglichkeiten, die Ausführungszeit hoch zu setzen - was ich nicht besonders schön finde.
Leider weiß ich nicht, wie du genau den Import löst.
Läuft das per MySQL und INSERT's?

Wenn ja, dann schau dir mal folgende Funktion an:
http://dev.mysql.com/doc/refman/5.1/de/load-data.html
Bitte warten ..
Mitglied: ottscho
08.03.2013 um 09:12 Uhr
danke für dein input.

Es läuft über eine API der Shopschnittstelle.
Hinter der API stehen dann MYSQL INSERTS und UPDATES.

Die API selbst kann ich nicht anpassen.
Bitte warten ..
Mitglied: flow.ryan
08.03.2013 um 09:16 Uhr
Ah okay,

vielleicht wäre noch folgendes möglich:

Du durchläufst die 5000 INSERTs und nimmst dann die ersten 5000 Einträge aus der Datei raus.
Somit wird die Datei kleiner und du kannst dir die Durchläufe der Schleife sparen.
Bitte warten ..
Mitglied: nxclass
08.03.2013 um 09:17 Uhr
Das Ganze läuft über ein Script, welches sich wegen Servertimeout immer wieder selbst aufruft
... umgehen kann man dies in dem man das php Skript direkt auf der Konsole aufruft. Oder man macht den Shell Aufruf aus deinem Web-PHP Skript
01.
$return = `nohup php mein_scipt.php >stdout.log 2>stderr.log </dev/null & echo $!`;
so bekommst du die Prozess ID zurück und hast die Ausgaben in Log Dateien.
Bitte warten ..
Mitglied: hmarkus
08.03.2013, aktualisiert um 10:05 Uhr
Guten Morgen,
Zitat von ottscho:
...
Jetzt meine Frage. Je länge, das Script läuft, um so langsamer wird es bei den letzte Datensätzen. Da ja z.B bei
dem Offset 50000, davor in der Schleife erst mal 49999 übersprungen werden, bis dann ab 50000 die nächsten 500
importiert werden.

Es muss doch möglich sein, direkt den Einstiegspunkt mitzugeben. So dass nicht erst die bereits importierten Datensätze
ich hab von PHP keine Ahnung, soviel vorweg

ich würde, wenn ich sowas mit Perl mache, einen etwas anderen Ansatz wählen (oder zumindest ausprobieren).
Eine Schleife 50000 mal zu durchlaufen kostet Zeit. Stattdessen würde ich die letzte verarbeitet Zeile (oder eine Teilzeichenkette daraus) in einer Datei speichern. Wenn das Programm wieder startet, dann öffnet es die csv-Datei und liest die Zeichenkette ein. Wenn nun in der geöffneten Datei nach der Zeichenkette gesucht wird (PHP wird ja eine Variante von grep haben), dann geht das höchstwahrscheinlich erheblich schneller als Schleifendurchlauf. Die Geschwindigkeit hängt auch davon ab, welchen Teilstring man verwendet (sollte so verschieden als möglich von anderen Strings sein).


Gerade ausprobiert mit Perl, es bringt nichts.

Markus
Bitte warten ..
Mitglied: Lochkartenstanzer
08.03.2013 um 09:57 Uhr
Moin,

was ich mich frage ist, warum man eine Interpretersprache dafür nimmt? Ich würde da einfach ein C-Binary daraus machen (notfall smit PHC & gcc) und dann das aufrufen.

Was spricht eigentlich dagegen die Eingangsdatei einfach in Häppchen zu je 500 Datensätzen (als Einzeldateien) aufzuteilen und dann den Import auf jeweils diese Häppchen loszulassen?

lks
Bitte warten ..
Mitglied: ottscho
08.03.2013 um 10:05 Uhr
moin,


>was ich mich frage ist, warum man eine Interpretersprache dafür nimmt? Ich würde da einfach ein C-Binary daraus >machen (notfall smit PHC & gcc) und dann das aufrufen.

Naja, die Shopschnittstelle für den Import ist eine API in PHP.

>Was spricht eigentlich dagegen die Eingangsdatei einfach in Häppchen zu je 500 Datensätzen (als Einzeldateien) >aufzuteilen und dann den Import auf jeweils diese Häppchen loszulassen?

nichts. so läuft im moment der erste ansatz. wir machen 10t csv Splittdateien. Sprich die Eingangsdatei mit den 120t Artikel wird in 12 Einzeldateien gesplittet.

Dies sollte schon sehr viel Zeit sparen.
Bitte warten ..
Mitglied: Lochkartenstanzer
08.03.2013 um 10:47 Uhr
Zitat von ottscho:
moin,


>was ich mich frage ist, warum man eine Interpretersprache dafür nimmt? Ich würde da einfach ein C-Binary daraus
>machen (notfall smit PHC & gcc) und dann das aufrufen.

Naja, die Shopschnittstelle für den Import ist eine API in PHP.

Da gibt es trotzdem Möglichkeiten, wie gesagt zur Not mal PCH ausprobieren.


>Was spricht eigentlich dagegen die Eingangsdatei einfach in Häppchen zu je 500 Datensätzen (als Einzeldateien)
>aufzuteilen und dann den Import auf jeweils diese Häppchen loszulassen?

nichts. so läuft im moment der erste ansatz. wir machen 10t csv Splittdateien. Sprich die Eingangsdatei mit den 120t Artikel
wird in 12 Einzeldateien gesplittet.

Dies sollte schon sehr viel Zeit sparen.

Sind die CSV-Datensätze "einzeilig", d.h. pro Datensatz eine zeile oder sind da zeilenumbrüche drin? Wenn sie einzeilig sind, könnte man durch ein einfaches

cat csv-datei | head -n start+500 | tail -n 500 >temp.csv
eine temporäre Datei erzeugen, die genau die gerade zu bearbeitenden Sätze enthält und schnell genug sein sollte

lks
Bitte warten ..
Mitglied: hmarkus
08.03.2013, aktualisiert um 10:57 Uhr
Zitat von Lochkartenstanzer:
...
> cat csv-datei | head -n start+500 | tail -n 500 >temp.csv 
> 
eine temporäre Datei erzeugen, die genau die gerade zu bearbeitenden Sätze enthält und schnell genug sein sollte
das sieht gut aus, ist jedenfalls dreimal so schnell wie mein Versuch mit Perl
den Teil mit cat bis zum ersten '|' kann man auch weglassen und direkt die Ausgabe von head nach tail pipen.

Spricht etwas dagegen, keine temporäre Datei anzulegen, sondern die 500 Zeilen direkt an das PHP-Programm zu übergeben? Dazu bräuchte man ein kleines Shellskript welches dann auch das PHP-Programm aufruft.

Markus
Bitte warten ..
Mitglied: ottscho
08.03.2013 um 10:57 Uhr
cat csv-datei | head -n start+500 | tail -n 500 >temp.csv
Sind Einzeilig. Das sieht gut aus. So werden wir es probieren.
Bitte warten ..
Mitglied: ottscho
08.03.2013 um 10:59 Uhr
Zitat von hmarkus:
> Zitat von Lochkartenstanzer:
> ...
>
> > cat csv-datei | head -n start+500 | tail -n 500 >temp.csv 
> > 
>
> eine temporäre Datei erzeugen, die genau die gerade zu bearbeitenden Sätze enthält und schnell genug sein
sollte
das sieht gut aus, ist jedenfalls dreimal so schnell wie mein Versuch mit Perl
den Teil mit cat bis zum ersten '|' kann man auch weglassen und direkt die Ausgabe von head nach tail pipen.

Spricht etwas dagegen, keine temporäre Datei anzulegen, sondern die 500 Zeilen direkt an das PHP-Programm zu übergeben?
Dazu bräuchte man ein kleines Shellskript welches dann auch das PHP-Programm aufruft.

Markus

Nein, spricht nichts dagen.
Bitte warten ..
Mitglied: hmarkus
08.03.2013, aktualisiert um 12:05 Uhr
Zitat von ottscho:
...
Nein, spricht nichts dagen.
ich wollte eigentlich genauer sagen: man reduziert damit die Anzahl der Dateiöffnungen um die Hälfte. Außerdem werden diese nur noch von head gemacht was viel schneller sein dürfte als mit PHP.

Interessantes Thema übrigens, mich würde interessieren, wenn es fertig ist, wie es mit der tatsächlichen Zeitersparnis gegenüber Eurem ersten Ansatz aussieht.

Markus
Bitte warten ..
Mitglied: Lochkartenstanzer
08.03.2013 um 11:05 Uhr
Zitat von hmarkus:
> Zitat von Lochkartenstanzer:
> ...
>
> > cat csv-datei | head -n start+500 | tail -n 500 >temp.csv 
> > 
den Teil mit cat bis zum ersten '|' kann man auch weglassen und direkt die Ausgabe von head nach tail pipen.

Normal hätte ich das als
cat csv-datei | head -n start+500 | tail -n 500 | tee temp.cs
geschrieben.

Ich benutze gern cat, weil ich solche Ketten meist "interaktiv" aufbaue und so einfach ein weiteres "|" mit Befehlen zwischenreinsetzen kann, ohne die schon vorhanden Kette groß verändern zu müssen. iIn der endgültigen Variante kann man natürlich dann verschiedene Pipe-Stufen "wegkürzen".

lks
Bitte warten ..
Mitglied: Guenni
10.03.2013, aktualisiert um 17:45 Uhr
Hi ottscho,

sofern nur die Importroutine das Timeout-Problem verursacht:

- Definiere einen Zähler für alle Zeilen
- Definiere einen Wert für die Zeilen, die pro Import importiert werden sollen

Wenn der Zähler_für_alle_Zeilen modulo_dividiert Zeilen_pro_Import 0 ergibt . . .

- Importroutine aufrufen
- Zähler_für_alle_Zeilen auf 0 setzen

Anschließend werden die letzten Zeilen eingelesen(importiert).

Beispiel:

01.
<?php 
02.
$lines=0; 
03.
$max_lines=500; 
04.
$f=fopen("doku.txt","r"); 
05.
	while($line=fgets($f)){ 
06.
	 $line_arr[$lines]=$line; 
07.
	 $lines++; 
08.
		if($lines%$max_lines==0){ 
09.
		 echo "// Importroutine: "; 
10.
		 echo $lines.' Zeilen werden importiert.<br>'; 
11.
			$lines=0; 
12.
13.
14.
	/* 
15.
	* Restliche Zeilen importieren 
16.
	*/ 
17.
	while($line=fgets($f)){ 
18.
	 $line_arr[$lines]=$line; 
19.
	 $lines++; 
20.
21.
	if($lines>0){ 
22.
	 echo "// Importroutine: "; 
23.
	 echo $lines.' Zeilen werden importiert.<br>'; 
24.
25.
fclose($f); 
26.
?>
Gruß
Günni
Bitte warten ..
Mitglied: ottscho
11.03.2013 um 08:04 Uhr
Moin Zusammen,

danke noch mal für die vielen Inputs von euch.
Auf die Schnell konnte ich es nicht über eine Consolen Anwendung umsetzen. Problem ist, dass die PHP Datei innerhalb eines Plugin System läuft und die API der Shopschnittstelle dort aus einer anderen Classe geladen wird.
Dazu fehlt mir einfach das Knowhow.

Ich habe es nun mit einem Byte Datenzeiger umgesetzt (fseek). Somit fange ich immer genau an der Stelle an zu lesen, wo ich davor aufgehört habe. D.h. ich muss nicht immer alle Datensätze überspringen.

Als Consolen Script muss es aber früher oder später laufen. Da später mehrere Shops damit bedient werden sollten.
Dann ist es über ein PHP Script, welches über eine URL aufgerufen wird mit der Zeit zu unübersichtlich.

Danke euch...
Bitte warten ..
Neuester Wissensbeitrag
Windows 10

Powershell 5 BSOD

(8)

Tipp von agowa338 zum Thema Windows 10 ...

Ähnliche Inhalte
Batch & Shell
Schleife mit todos CMD

Frage von TommyDerWalker zum Thema Batch & Shell ...

Batch & Shell
gelöst Fehler in Schleife (2)

Frage von miczar zum Thema Batch & Shell ...

Windows 7
gelöst Bestimmter Benutzer kann sich nicht anmelden (6)

Frage von xbast1x zum Thema Windows 7 ...

Heiß diskutierte Inhalte
Microsoft
Ordner mit LW-Buchstaben versehen und benennen (20)

Frage von Xaero1982 zum Thema Microsoft ...

Outlook & Mail
gelöst Outlook 2010 findet ost datei nicht (19)

Frage von Floh21 zum Thema Outlook & Mail ...

Netzwerkmanagement
gelöst Anregungen, kleiner Betrieb, IT-Umgebung (18)

Frage von Unwichtig zum Thema Netzwerkmanagement ...

Festplatten, SSD, Raid
M.2 SSD wird nicht erkannt (14)

Frage von uridium69 zum Thema Festplatten, SSD, Raid ...