Script-Tuning |
corny
Mausakrobat Threadstarter
Beiträge: 203 |
Hallo erstmal.
Ich habe ein Problem mit einem Sript. Wenn ich dieses Script von nem Cronjob ausführen lasse (ist eigentlich egal ob von nem Cronjob oder nicht), dann belegt es zuviel Ram. Mein Hoster hat das leider begrenzt, so dass das Script nach einer bestimmten Zeit automatisch abgebrochen wird und einen 500er liefert.
Nun bleibt mir nichts anderes übrig als das Script zu tunen.
Im Ur-Zustand war es ein Script, dass 3 Dateien öffnet und diese in die Datenbank einpflegt. Nun habe ich es schon so verändert, dass es 3 Scripte mit jeweils einer Datei sein. Das klappt leider nicht; da eine der Dateien unverhältnismäßig groß ist.
Jetzt muss ich also am Script selber etwas ändern. Nun also zu meiner Frage:
Ist es Arbeitsspeicher-technisch sinnvoller erst die Tabelle in der Datenbank zu leeren und dann zeilenweise wieder zu füllen (weil nur die neuen Daten sind relevant), oder ist es besser das ganze per "UPDATE" zu machen?
Hättet ihr sonst noch Ideen, wie man das Problem beheben/umgehen kann?
Gruß, Corny
---
www.webworxis.de
|
 Profil
E-Mail
Website
Editieren
Zitieren
|
chip
Foren-Team
Beiträge: 419 |
Ich verstehe Dein Problem noch nicht ganz. Denn wenn Du Dateien einliest kommt es an dieser Stelle (also beim Einlesen) ja zu dem besagten Fehler und nicht beim Update der MySQL-Tabelle.
Meinst Du am Ende vielleicht auch REPLACE anstatt UPDATE? Denn ein UPDATE ist immer sinnvoller als alles zu löschen und neu zu schreiben.
---
Diese Nachricht wurde geändert von: chip |
 Profil
Website
Editieren
Zitieren
|
corny
Mausakrobat Threadstarter
Beiträge: 203 |
Aso, ok...
Das es bei UPDATE immer besser ist erst zu löschen und neu zu erstellen wusste ich nicht.
Und wie ist es bei REPLACE?
Ist das sinnvoll?
Sonst noch Tuning-Ideen?
Soll ich das Script mal posten?
---
www.webworxis.de
|
 Profil
E-Mail
Website
Editieren
Zitieren
|
chip
Foren-Team
Beiträge: 419 |
corny schrieb am 04.08.2007 20:05
Das es bei UPDATE immer besser ist erst zu löschen und neu zu erstellen wusste ich nicht. |
Ganz im Gegenteil. Das ist es nicht, was ich gesagt habe! UPDATE ändert Werte bei bereits vorhandenen Zeilen. Alles zu löschen und neu zu erstellen ist total sinnlos.
REPLACE fügt neue Zeilen ein, wobei bereits bestehende mit den selben Werten ignoriert werden (also nicht überschrieben werden).
---
|
 Profil
Website
Editieren
Zitieren
|
corny
Mausakrobat Threadstarter
Beiträge: 203 |
Naja, bei UPDATE müsste ich ja erst abfragen, ob sich, und wenn ja was sich verändert hat.
Jetzt ist die Frage was günstiger ist.
Ist UPDATE auch besser, wenn ich vorher vergleichen muss?
---
www.webworxis.de
|
 Profil
E-Mail
Website
Editieren
Zitieren
|
chip
Foren-Team
Beiträge: 419 |
Bei UPDATE ist wie bei allen anderen Abfragen auch, eine WHERE-Klausel möglich, die Dir entsprechende Vergleichsmöglichkeiten bietet.
---
|
 Profil
Website
Editieren
Zitieren
|
corny
Mausakrobat Threadstarter
Beiträge: 203 |
ja, das weiß ich ja, die Einträge sind ja auch alle Nummeriert.
Die Frage ist nur, ob es besser wäre, mit diesem Vergleich ...
Anbei das Script, falls dir sonst noch was auffällt, was man verbessern könnte...
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17: |
$file = $phpbb_root_path . $import_path . "village.txt";
$sql = "TRUNCATE TABLE `".VILLAGE_TABLE;
mysql_query($sql);
$filearray = fopen ($file, "r");
while (!feof($filearray)) {
$line = fgets($filearray);
list($id, $name,$x, $y, $player, $points, $rank) = explode(',', $line);
$name = datadecode($name);
$name = addslashes($name);
$sql = "INSERT INTO " . VILLAGE_TABLE . " SET id='$id', name='$name', x='$x', y='$y', player='$player', points='$points', rank='$rank'";
$db->sql_query($sql);
}
fclose ($filearray);
|
$id, $name,$x, $y und $player würde sich dabei, wenn alles richtig läuft nie verändern, nur $points und $rank.
Gibt es eventuell eine Möglichkeit die Ram, die ein Script belegt mittendrin zurück zusetzten, oder so?
---
www.webworxis.de
Diese Nachricht wurde geändert von: corny |
 Profil
E-Mail
Website
Editieren
Zitieren
|
chip
Foren-Team
Beiträge: 419 |
file_get_contents() und explode("\n", $bla) wären hier die bessere Wahl, anstatt immer Zeile für Zeile aus der Datei zu holen.
Da, wie Du sagst $id immer gleich bleibt, mach es doch so:
1: | "UPDATE " . VILLAGE_TABLE . " SET points = '".$points."', rank = '".$rank."' WHERE id = '".$id."' LIMIT 1" |
// Edit: LIMIT hinzugefügt
---
Diese Nachricht wurde geändert von: chip |
 Profil
Website
Editieren
Zitieren
|
Ori
Mausakrobat
Beiträge: 162 |
Für ein paar Erdnüsse kannst Du noch "-Strings in '-Strings umwandeln, solange Du das Einsetzen von Variablen nicht brauchst.
file_get_contents lädt die (nach corny überdimensional große) Datei in den RAM, was wohl die Providervorgabe sprengen dürfte, insofern ist zeilenweises Abarbeiten vermutlich nötig (und bei einer riesigen Datei wohl auch schneller als das Zerlegen eines gewaltigen Strings).
Wenn die id ausreicht, um einen Spieler zu identifizieren (was irgendwie Sinn macht), würde es reichen, wenn Du nur diese abspeicherst, um beim Einlesen Zeit zu gewinnen (die anderen Daten stehen ja in der Datenbank).
|
 Profil
E-Mail
Website
Editieren
Zitieren
|
progrookie
Fachidiot
Beiträge: 127 |
1: | $arContent = file($this->Path); |
...was würde dagegen sprechen beispeilsweise so die Datei durch zulesen?
Datei wird ín ein Array hinein geladen, welches man auch Zeilenweise durchgehen kann.
---
|
 Profil
E-Mail
Website
Editieren
Zitieren
|
chip
Foren-Team
Beiträge: 419 |
Ori schrieb am 08.08.2007 00:48
file_get_contents lädt die (nach corny überdimensional große) Datei in den RAM, was wohl die Providervorgabe sprengen dürfte, insofern ist zeilenweises Abarbeiten vermutlich nötig (und bei einer riesigen Datei wohl auch schneller als das Zerlegen eines gewaltigen Strings). |
Ist es hier nicht das selbe? Dann wird eben Zeile für Zeile eingelesen und belastet trotzdem den RAM.
$id, $name,$x, $y und $player würde sich dabei, wenn alles richtig läuft nie verändern, nur $points und $rank. |
Warum wird es dann in die Textdatei geschrieben und ausgelesen?
---
|
 Profil
Website
Editieren
Zitieren
|
corny
Mausakrobat Threadstarter
Beiträge: 203 |
chip schrieb am 08.08.2007 11:21
$id, $name,$x, $y und $player würde sich dabei, wenn alles richtig läuft nie verändern, nur $points und $rank. |
Warum wird es dann in die Textdatei geschrieben und ausgelesen? |
Zia, da kann ich leider gar nichts dran ändern.
Der Inhalt der Textdatei wird mir so geliefert wie er ist.
Mein Job ist es nur diese Textdatei möglichst, RAM, schonend in die DB zu befördern.
---
www.webworxis.de
|
 Profil
E-Mail
Website
Editieren
Zitieren
|
Ori
Mausakrobat
Beiträge: 162 |
chip schrieb am 08.08.2007 11:21
Ori schrieb am 08.08.2007 00:48
file_get_contents lädt die (nach corny überdimensional große) Datei in den RAM, was wohl die Providervorgabe sprengen dürfte, insofern ist zeilenweises Abarbeiten vermutlich nötig (und bei einer riesigen Datei wohl auch schneller als das Zerlegen eines gewaltigen Strings). |
Ist es hier nicht das selbe? Dann wird eben Zeile für Zeile eingelesen und belastet trotzdem den RAM. |
Via file_get_contents wird die gesamte Datei auf einmal in den RAM gelesen. Wenn die Datei zeilenweise gelesen wird, ist nicht alles gleichzeitig im RAM, sondern nur die gelesene Zeile (und ein bisschen für die Verwaltung des Dateizugriffs, das ist aber vernachlässigbar).
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11: | $filearray = fopen ($file, 'r');
while (!feof($filearray))
{
$line = fgets($filearray);
$arr = explode(',', $line);
$sql = 'UPDATE ' . VILLAGE_TABLE . ' SET points = \'' . $arr[5] . '\', rank = \'' . $arr[6] . '\' WHERE id = \'' . $arr[0] . '\' LIMIT 1';
$db->sql_query($sql);
}
fclose ($filearray); |
Ein paar Kommentare dazu: Ich vertraue list() nicht, weil das wohl intern in einfache Variablenzuweisungen umgemünzt wird, wir aber nur drei der sieben Werte wissen wollen. Abspeichern der Variablen für einmalige Verwendung bringt auch keinen Geschwindigkeitszuwachs.
Stehen in der Textdatei eigentlich auch neue Einträge, die vorher nicht in der Datenbank standen? Und: Wie groß ist die Textdatei eigentlich?
|
 Profil
E-Mail
Website
Editieren
Zitieren
|
corny
Mausakrobat Threadstarter
Beiträge: 203 |
Die Datei selber(die größte) ist 11,39 mb groß.
offiziell stehen mir 9mb RAM zur Verfügung.
Das Script wird aber erst bei Überschreiten der 10 MB abgebrochen.
Ja, es gibt auch Einträge in der Datei, die komplett in die DB übernommen werden müssen, also nicht nur geupdated werden müssen.
ist es möglich, dass man die Datei splittet und bei jedem Scriptaufruf nur eine der Dateien eingelesen werden? Ist es dann möglich, dass sich das Script nach Durchlauf einfach erneut aufruft?
---
www.webworxis.de
|
 Profil
E-Mail
Website
Editieren
Zitieren
|
raiserle
Mausakrobat
Beiträge: 172 |
Hab jetzt nicht alles durchgelesen, nur den letzten Beitrag.
Aber mein Vorschlag...
Öffne die Datei, und lies einen Datensatz ein, ab letzter Position vom Filepointer. Wenn noch ein Datensatz vorhanden ist, weitermachen .. nächsten Datensatz holen und letze Position vom Dateiziger holen.
So wie ich das mitbekommen habe, willst den ja in eine DB haben.
Also schreib den Datensatz in die DB und speicher dir die Position des Filepointers.
schliesse die Datei.
Mach ein header() auf das selbige Script.
So sollte ein DS nach dem anderen in die DB wandern, ohne das du die komplette Datei in den Speicher haust.
Gruß raiserle
---
Irren is Menschlich
Wer andern eine Grube gräbt,
sollte darüber nachdenken,
ob sie tief genug ist!!!!
Kameradschaft ist, wenn der
Kamerad schafft !!!!
|
 Profil
Editieren
Zitieren
|