[PHP & MySQL] Performance

ChristianK

Well-known member
ID: 85965
L
25 Mai 2006
92
1
Hallo,

ich programmiere derzeit ein Brwoseronlinespiel. Leider kenne ich mich nicht so gut aus, was ein Server so alles leisten kann.

Ich willl folgendes machen: Ein User bekommt ein 20x20 großes Feld, welches er mit Gebäuden bebauen kann. Diese sollten dann gespeichert werden ABER genau auf der Position die man angeklickt hat.

Wie sollte ich dies Speichern lassen, und wieder ausgeben lassen? Ich habe mir gedacht ich schreibe für jedes gebaute Gebäude in SQL je eine Zeile. Weiterhin für jedes Feld ein Eintrag in der Session, damit ich MySQL abfragen spare. Denn ich werde öfters Informationen über das Feld abfragen.

Ich denke jedoch meine Theorie ist nicht so gut, da dann gut 400 Einträge in die Session kommen allein von den Bauplätzen. Diese 400 Einträge, haben selbst noch Untereinträge mit Informationen z. B. ob der Platz bebaut ist.
Da die ganzen Plätze noch ins SQL kommen (400 bei vollbebauung) und das bei den maximalen Festungen von 10.000 der FAll sein kann, wären dann im SQL 4.000.000 Eintäge.

Ist dies zu viel für MySQL oder leidet dadurch die Geschwindigkeit? Oder gibt es noch andere Möglichkeiten wie ich mein Problem lösen könnte?
400 Sessioneinträge mit jeweils 5 Untereinträgen und 4.000.000 MySQL Einträge ist ja ziemlpich viel !!

Hoffe ihr könnt mir helfen und schon mal danke das ihr meinen lannnngen Beitrag gelesen habt!!!

Christian
 
ChristianK schrieb:
Wie sollte ich dies Speichern lassen, und wieder ausgeben lassen? Ich habe mir gedacht ich schreibe für jedes gebaute Gebäude in SQL je eine Zeile. Weiterhin für jedes Feld ein Eintrag in der Session, damit ich MySQL abfragen spare. Denn ich werde öfters Informationen über das Feld abfragen.
Das Prinzip pro Gebäude ein Datensatz is richtig.
Wenn du alles in der Session machen willst, auch gut.

Beim Einloggen lies die Daten aus der DB und übertrage sie in die Session. Änderungen in der Session auch gleich in die DB schreiben, aber sonst nichts mehr aus der Datenbank lesen. Wenn du alles richtig machst, müsste das gehen.
ChristianK schrieb:
Diese 400 Einträge, haben selbst noch Untereinträge mit Informationen z. B. ob der Platz bebaut ist.
Naja, wenn der Platz nicht bebaut is, hast du auch keinen Eintrag, oder ? ;)
ChristianK schrieb:
400 Sessioneinträge mit jeweils 5 Untereinträgen und 4.000.000 MySQL Einträge ist ja ziemlpich viel !!
Die Sessioneinträge werden nur durch den PHP-Speicher limitiert, der sollte für ein mehrdimensionales Array [400][5] reichen. Probiers einfach aus:
PHP:
$dummy=array();
for($i=0;$i<400;$i++)
{
  $dummy[i]=array();
  $for($j=0;$j<5;$j++)
    $dummy[i][j]=str_repeat("X",128);
}
MySQL ist für eine Millionenzahl von Datensätzen pro Tabelle optimiert.
Wenn du die Indizes richtig setzst, ist es kein Problem, weil du ja nur einen User ("Festung") auf einmal abfragst.

P.S.
ChristianK schrieb:
schon mal danke das ihr meinen lannnngen Beitrag gelesen habt!!!
Du nennst das lang ? :LOL:
 
Ja, finde dies schon lang ;)

Habe den Code mal ausprobiert, also lokal geht er schnell mit den Arrays erstellen :D


PHP:
$dummy=array();
$dummy=array();
for($i=0;$i<400;$i++)
{
  $dummy[$i]=array();
  for($j=0;$j<5;$j++)
    $dummy[$i][$j]=str_repeat("X",128);
}

Also würde MySQL die Millionen Einträge überhaupt nichts ausmachen??
 
ChristianK schrieb:
Also würde MySQL die Millionen Einträge überhaupt nichts ausmachen??
Richtig.

Ich glaube, du guckst dich mal auf der Webseite von MySQL um und liest dich etwas ein. Da werden auch viele Performance-Fragen beantwortet. Außerdem mal bei den Indizes vorbeigucken.
 
Bist du dir sicher dass du die Gebäudedaten in eine Session laden willst? So lassen sie sich leicht manipulieren => cheaten

Und wenn du deswegen die Daten dann jedesmal überprüfen müsstest bringt das im Endeffekt wenig. Höchstens zur Ausgabe wenn man sich seine 20x20 Felder anguckt. Aber lass nie etwas nach diesen angaben berechnen ohne sie zu prüfen.
 
Wie soll man denn die Einträge in der Session fälschen? Die liegen doch auf den Server? Dachte da wären sie sicher..
 
ChristianK schrieb:
Wie soll man denn die Einträge in der Session fälschen? Die liegen doch auf den Server? Dachte da wären sie sicher..
Von dem gehe ich normal auch aus ;)
 
Ich würde mal bei ~4mio Datensätzen überprüfen, ob es eventuell schneller ist, das Array einmal zu erzeugen und serialisiert abzuspeichern.

Die Ergebnisse würden mich auch interessieren :mrgreen:
 
theHacker schrieb:
Hast dus schon mal geschafft, hier im vB deine UserID auf 1 zu setzen und dir so klamm's Admin-Rechte zu holen ? ;)

da muss mann nur lukas net fragen da richtet er einen bestimmt nen eigene sforum ein mit adminrechten ^^
 
php in memory sessions

hallo,

wenn du alles in einer php - session speicherst, dann hast du regelmäßig zugriffe auf deine Platte und unendlich viele Files im /tmp/ ordner. alternativ kannst du ja noch die sessiondaten in der db ablegen - dies würde evtl. die menge der zu durchsuchenden daten minimieren (wenn nicht zu viele online sind).

wenn du mit php-sessions arbeiten willst, dann schaue dir unbedingt shared memory allocation anschauen:

<zitat>
Um für die Speicherung von Sessions die shared memory allocation (mm) zu benutzen, müssen Sie PHP mit der Option --with-mm[=DIR] konfigurieren.
</zitat>

Dies hat den grossen Vorteil, dass die Sessions im Speicher gehalten werden - und das ist das schnellste :)

In der Datenbank würde ich auch nur die bebauten Felder abspeichern - leere Felder können dir egal sein.

hoffe es hilft dir ein bisschen weiter.
 
Also ich hab gestern mal zum Testen die Datenbank mit 4Millionen Einträgen voll gemacht, dauerte 20 Minuten :p

Dann wenn ich nach etwas suchen will in der DB dauert es ca. 4 Sekunden im Schnitt. Ich glaube, ich schreibe nur die Gebäudetypen ins SQL. Das heißt: z. B. User "Test" baut einen Holzfäller. Dieser kommt ins SQL falls noch kein Eintrag von User "TEst" mit den Geb "Holzfäller" vorhanden ist. Dann gibts ein Feld Koadinaten wo dann drinn steht: X:5|Y:9|Arbeiter:9|Vorhanden:10
So könnte ich dann die Gebäude Speichern lassen. Wenn es mehrer gibt dann vieleicht so getrennt: X:5|Y:9|Arbeiter:9|Vorhanden:10;X:3|Y:2|Arbeiter:3|Vorhanden:5 . DAnn würde ich beim Einloggen diese Splitten und in die Session laden. Nur dann gibt es ein Problem: Wie kann ich dann schnell und einfach da was ändern? Dann müsste ich mir alle Daten von den ganzen Gebäudetyp aus der Session laden und den String dann neuschreiben lassen.

Wird es noch eine einfachere möglichkeit geben?
 
ChristianK schrieb:
Dann gibts ein Feld Koadinaten wo dann drinn steht: X:5|Y:9|Arbeiter:9|Vorhanden:10
Vergiss das ganz schnell 8O
Das widerspricht ja wohl allen Normalformen.

Hast du die Indizes passend gesetzt ? Ich probier das jetzt auch mal aus, wie lange das bei mir dauert.
 
Ich doppelposte mal, weils solang gedauert hat:

Ich hab für die 4.000.000 INSERT-Queries jetzt ca. ne halbe Stunde gebraucht, v.a. weil mir das Script mehrmals abgebrochen is. Muss dazu sagen, ich hatte Zufallsgeneratoren mit im Einsatz.

Meine Tabelle:
CREATE TABLE `largetable` (
`x` INT(10) UNSIGNED NOT NULL,
`y` INT(10)
UNSIGNED NOT NULL,
`player` INT(10)
UNSIGNED NOT NULL,
`building` SMALLINT(5)
UNSIGNED NOT NULL,
`workers` SMALLINT(6) NOT NULL,
PRIMARY KEY (`x`,`y`),
INDEX
`player` (`player`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
COLLATE=latin1_german1_ci
Gefüllt so:
PHP:
set_time_limit(0);
for($y=0;$y<2000;$y++)
  for($x=0;$x<2000;$x++)
    mysql_query("INSERT INTO `largetable` (`x`,`y`,`player`,`building`,`workers`) VALUES ($x,$y,".(rand()%2000).",".(rand()%100).",".(rand()%50).")");
D.h. alle 4 Millionen Felder sind auf 2000 verschiedene Spieler aufgeteilt.
Jeder Spieler hat damit durchschnittlich 2000 Gebäude.

Abfrage nach allen Gebäuden eines Spielers:
SELECT `x`,`y`,`building`,`workers` FROM `largetable` WHERE `player`=215
dauert durchschnittlich 2500µs

Abfrage eines Felds:
SELECT `player`,`building`,`workers` FROM `largetable` WHERE `x`=100 AND `y`=200
dauert durchschnittlich 700µs

edit:
Doch kein Doppelpost mehr, so lang hab ich jetzt formatiert :biggrin:
 
Also meint ihr, ich sollte es mit den 4 Millionen Einträgen probieren?

Warum soll ich mein Vorschlag vergessen? Ich habe ihn schon lange in Gebäudebau drin. Und zwar gibts in SQL ein Feld namens kosten und dort steht auch Holz:500|Stein:200| drin, und es geht auch gut damit. So spare ich Felder im SQL ;)

Danke das du das ganze durchgerechnet hast :) Nur ich weiß leider nicht was "µs" für eine Zeit ist. Sind das ms? Ich probiere das gleiche nochher auch noch mal aus mit deinen Code.
 
ChristianK schrieb:
Warum soll ich mein Vorschlag vergessen? Ich habe ihn schon lange in Gebäudebau drin. Und zwar gibts in SQL ein Feld namens kosten und dort steht auch Holz:500|Stein:200| drin, und es geht auch gut damit. So spare ich Felder im SQL ;)
Und genau das darfst du nicht. Du sollst nicht sparen, sondern atomar speichern.
Lies dir die Normalformen durch :pray:
ChristianK schrieb:
Nur ich weiß leider nicht was "µs" für eine Zeit ist. Sind das ms?
Da hat wohl einer in Mathe ned aufgepasst :p
1 µs = 0,001 ms = 0,000001 s
siehe unbedingt https://www.klamm.de/forum/showpost.php?p=110401&postcount=7
 
Aber wenn ich es so mache wie du meinst, wären das dan locker 60Felder unter einen Table!

Doch, habe aufgepasst ^^ Leider wohl nicht so richtig da es µs heißt nicht µ. Auf jeden wall ging es ja dann richtig schnell mit den SQL?
 
ChristianK schrieb:
Warum soll ich mein Vorschlag vergessen? Ich habe ihn schon lange in Gebäudebau drin. Und zwar gibts in SQL ein Feld namens kosten und dort steht auch Holz:500|Stein:200| drin, und es geht auch gut damit. So spare ich Felder im SQL ;)

Naja, der Aufwand beim Verarbeiten der Daten ist erheblich größer und trägt nicht wirklich zu übersichtlichem Code bei.

Wenn bei dir in kosten Holz und Stein immer benötigt wird, dann nehm es ruhig als einzelnes Feld auf.
Wenn Holz und Stein nicht immer benötigt wird, dann mach ruhig eine Tabelle

kosten_eigenschaften
objekt_id | eigenschaft | wert

Damit fährt man ganz gut ...