Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 13

Thema: Paralleler Datenbankzugriff

  1. #1
    Youngster
    Registriert seit
    13.12.2009
    Beiträge
    14
    Danke
    0
    Bekam 0 mal "Danke" in 0 Postings

    Standard Paralleler Datenbankzugriff

    Hi!
    Ich bastle gerade an einem PHP-Skript zum auslesen von Spielstatistiken aus einer MySQL-Datenbank. Die Statistiken werden von einem Bot geschrieben, auf dessen Art und Weise die Tabelle zu schreiben ich keinen Einfluss habe. In der Datenbank gibt es eine Tabelle, die mit jedem Spiel 10 Zeilen, die den Statistiken der 10 Spieler aus dem Spiel entsprechen bekommt.
    Nun ist es natürlich so, dass es auch Spieler gibt, die mehrere Spiele spielen, also öfter in der Tabelle auftauchen. Ich möchte nun per PHP eine neue Tabelle erzeugen, die jeden Spieler nur einmal und in der entsprechenden Zeile die gesammten Statistiken des Spielers enthält.
    Mit jedem aufruf des Skripts, dass die zweite Tabelle in irgendeiner Art und Weise präsentiert, soll diese auch gleichzeitig aktualisiert werden. Da dies aber bei einer großen Spielzahl eher länger dauert und und ich das nicht bei jedem Seitenaufruf haben möchte, lese ich aus der ersten Tabelle nur bisher ungelesene Einträge aus, indem ich eine weitere Spalte "read" hinzufüge und diese auf nach dem lesen auf 1 setze. Die gelesenen Statistiken werden dann in die zweite Tabelle integriert.
    Und jetzt kommt das Problem:
    Es ist zwar unwahrscheinlich, aber darf nicht außer Acht gelassen werden, dass zwei gleichzeitig ausgeführte Skripte, die beide die ungelesenen Zeilen aus der ersten Tabelle in die zweite Tabelle integrieren wollen sich in die Quere kommen, das heißt sie lesen beide gleichzeitig und integrieren die Zeilen doppelt, was die zweite Tabelle verfälscht.
    Dass das möglich ist, habe ich mit diesem Skript ausprobiert:
    Code:
    <?php
    
    $test = $HTTP_GET_VARS['test'];
    
    if($test == 1)
    {
        $connection = mysql_connect("localhost", "root", "meinpasswort");
        mysql_select_db("test", $connection);
        mysql_query("UPDATE `test` SET `wert` = '1' WHERE `id` =1 LIMIT 1 ;", $connection);
        $a = time();
        for($i = 0; $i < 5; $i = time() - $a) {}
        mysql_query("UPDATE `test` SET `wert` = '42' WHERE `id` =1 AND `wert` = '1' LIMIT 1 ;", $connection);
        mysql_close($connection);
    }
    else
    {
        $connection = mysql_connect("localhost", "root", "meinpasswort");
        mysql_select_db("test", $connection);
        mysql_query("UPDATE `test` SET `wert` = '56' WHERE `id` =1 AND `wert` = '1' LIMIT 1 ;", $connection);
        mysql_close($connection);
    }
    
    ?>
    Jetzt zwei fragen:
    1. Wie kann ich das verhindern?
    2. Kann ich wenigstens davon ausgehen, dass der MySQL-Server zwei Queries, die auch nur ansatzweise miteinander zu tun haben, NACHEINANDER ausführt?

    Vielen Dank fürs Durchlesen!
    Achtung: Dies ist ein alter Thread im HTML und Webmaster Forum
    Diese Diskussion ist älter als 90 Tage. Die darin enthaltenen Informationen sind möglicherweise nicht mehr aktuell. Erstelle bitte zu deiner Frage ein neues Thema im Forum !!!!!

  2. #2
    Forum Guru Avatar von The User
    Registriert seit
    28.10.2007
    Ort
    Zwischen Pazifik und Atlantik...
    Beiträge
    4.044
    Danke
    0
    Bekam 0 mal "Danke" in 0 Postings

    Standard AW: Paralleler Datenbankzugriff

    1. Wie wäre es mit sleep(5)
    2. Du kannst nicht davon ausgehen, wenn du sie getrennt losschickst.
    Du kannst aber mehrere Queries durch ein Semikolon als Separator zusammenfügen. Alternativ kannst du sem_get, sem_acquire und sem_release verwenden. Achte aber darauf, dass sem_release immer aufgerufen wird.

  3. #3
    Youngster
    Themenstarter

    Registriert seit
    13.12.2009
    Beiträge
    14
    Danke
    0
    Bekam 0 mal "Danke" in 0 Postings

    Standard AW: Paralleler Datenbankzugriff

    1. Hatte ich zuerst, aber dann habe ich gedacht, sleep könnte vielleicht ein Sonderfall sein und habe es vorsichtshalber ersetzt.
    2. Ok danke, ich schau mir die Funktionen mal an.

  4. #4
    Unregistriert
    Gast

    Standard AW: Paralleler Datenbankzugriff

    Super, das klappt!
    Allerdings nicht auf meinem Localhost... ich hab irgendwie gelesen, dass ich da vielleicht noch was aktivieren muss oder so. Der Server ist auch nicht mehr so neu, Wamp5 1.6.4 kann der das überhaupt?

    Und gibt es nicht noch ne möglichkeit das direkt aufm MySQL-Server zu regeln? Für mich reicht das ja so eigentlich erstmal, aber es könnte ja auch von woanders drauf zugegriffen werden, zum beispiel per phpmyadmin, oder wird das da auch geregelt?

  5. #5
    Youngster
    Themenstarter

    Registriert seit
    13.12.2009
    Beiträge
    14
    Danke
    0
    Bekam 0 mal "Danke" in 0 Postings

    Standard AW: Paralleler Datenbankzugriff

    Ahhhh mist, dit war icke. (Scheiß Timeout)
    Sry for Tripplepost...

  6. #6
    König(in) Avatar von crAzywuLf
    Registriert seit
    03.02.2009
    Beiträge
    1.175
    Danke
    1
    Bekam 0 mal "Danke" in 0 Postings

    Standard AW: Paralleler Datenbankzugriff

    Schau doch mal hier: LOCK TABLES
    Das könnte die Lösung für dein Problem sein.
    Gruß crAzywuLf

  7. #7
    Forum Guru Avatar von The User
    Registriert seit
    28.10.2007
    Ort
    Zwischen Pazifik und Atlantik...
    Beiträge
    4.044
    Danke
    0
    Bekam 0 mal "Danke" in 0 Postings

    Standard AW: Paralleler Datenbankzugriff

    Die Semaphore stehen bei PHP nur unter Unixoiden zur Verfügung, warum auch immer. Ansonsten kannst du das von CrazyWulf ja mal testen. Oder einfach per ; zwei Queries zugleich abschicken.

  8. #8
    Youngster
    Themenstarter

    Registriert seit
    13.12.2009
    Beiträge
    14
    Danke
    0
    Bekam 0 mal "Danke" in 0 Postings

    Standard AW: Paralleler Datenbankzugriff

    Okay, also dieses "LOCK TABLES" scheint das zu sein, was ich brauche. Allerdings habe ich bei der Hälfte der Erklärung nur Bahnhof verstanden, weil ich auch in sachen SQL eigentlich keine Ahnung habe... Ich denke, ich könnte bei dieser Uptdate-Geschichte ein bisschen Hilfe gebrauchen...

    Ich erkläre das Problem noch mal ein bisschen genauer:
    Es geht um einen Bot, der im Warcraft 3 - Battle.net Spiele hostet und am Ende jedes Spiel die Datenbank aktualisiert. Das umfasst im wesentlichen vier Tabellen:

    games - ein neuer Eintrag
    dotagames - ein neuer Eintrag, wenn das Spiel ein Dotaspiel war (in der Regel immer)
    gameplayers - soviele neue Einträge, wie Spieler im Spiel waren
    dotaplayers - 10 neue Einträge, wenn das Spiel ein Dotaspiel war (in der Regel immer)

    Jeder Eintrag in jeder Tabelle hat natürlich eine fortlaufende Id zur eindeutigen Identifizierung. Jede der Tabellen mit Ausnahme der Tabelle "games" besitzt eine Spalte "gameid", in der die Id des zugehörigen Eintrags in der games-Tabelle steht.
    In der Tabelle "dotaplayers" gibt es eine Spalte "colour". Sie beinhaltet die Farbe des Spielers in Form einer Zahl von 1 bis 11 ohne 6. Da nach jedem Spiel 10 Spieler hinzugefügt werden, gibt es für alle Einträge mit der gleichen "gameid" jede Farbe genau einmal.
    In der Tabelle "gameplayers" gibt es diese Spalte "colour" ebenfalls. Hat ein Eintrag aus der Tabelle "gameplayers" die gleiche "gameid" und "colour", wie ein Eintrag aus der Tabelle "dotaplayers", dann handelt es sich um den selben Spieler in dem selben Spiel. Weil allerdings nicht jedes Spiel ein Dotaspiel ist (könnte ja mal passieren) und nicht jedes Dotaspiel mit 10 Spielern gespielt wird (es gibt also Dummyeinträge), gibt es nicht für jeden "gameplayer" einen "dotaplayer" und andersrum ebenfalls.
    Nun ist es außerdem so, dass der Name, der zur Identifikation des Spielers dient, NUR in der "gameplayers"-Tabelle in der Spalte "name" vorhanden ist. Er ist übrigens auch das einzige Feld, das ich von dieser Tabelle brauche, da die übrigen Statistiken für diese "Update-Geschichte" irrelevant sind.
    In der Tabelle "dotagames" sind drei Spalten wichtig. Die erste nennt sich "winner". Ist der Wert eines Eintrags hier 0, so wurde das Spiel nicht beendet und es gibt keine auswertbaren Statistiken. Ist der Wert 1 oder 2, so hat "Sentinel" oder "Scourge" gewonnen. Die Spalten "min" und "sec" beinhalten die Spieldauer in Minuten und Sekunden.

    Um zur Sache zu kommen:

    Ich möchte eine neue Tabelle erstellen, in der für jeden Spieler aus der "dotaplayers"-Tabelle, der mindestens ein Dotaspiel beendet hat (winner != 0), eine Zeile vorhanden ist. In dieser Zeile sollen einige Statistiken aus den Einträgen der beendeten Spiele in der "dotaplayers"-Tabelle summiert stehen. Außerdem sollen dort die Anzahl der Spiele, die Anzahl der Siege und die gesammte Spielzeit des Spielers stehen.

    Beispiel:
    Ein Spieler mit dem Nicknamen hans hat insgesammt 2 Dotapiele beendet, eins mit der Dauer 40:30, das andere mit der Dauer 29:30, 1 Spiel davon hat er gewonnen. Betrachte ich nur die Spalte "kills" in "dotaplayers" (es gibt noch mehr): Im ersten Spiel hat er 10 Kills bekommen, im zweiten 12.
    Der eintrag in der neuen Tabelle sieht also wie folgt aus:

    name: hans
    games: 2
    wins: 1
    playtime: 4200 (in Sekunden)
    kills: 22
    ...

    Außerdem sollen in die Tabellen noch ein paar Spalten eingetragen werden, die sich aus der Tabelle selbst ergeben, nämlich "winratio" (in diesem Fall 0.5), für alle Statistiken wie "kills" noch eine "-ratio" nach der Formel "kills / playtime * avaragegametime", wobei avaragegametime die durchschnittliche Dauer eines Dotaspiels ist, und noch eine Spalte, die ich "strength" getauft habe und für die ich mir eine komplexere Formel überlegt habe, die von "winratio", "games" und allen ratio-Statistiken wie "killratio" abhängt.

    So weit, so gut, aber wie realisiere ich das?
    Jedes mal, wen sich jemand eine Seite anschaut, die auf dieser Tabelle aufbaut, soll ein Query aufgerufen werden, der die Tabelle aktualisiert und nach einer gewissen Sortierung ausliest. Damit nicht jedesmal jedes Spiel und jeder Spieler ausgelesen wird, möchte ich die bereits gelesenen Spiele markieren, indem ich in der Tabelle "dotagames" eine neue Spalte "read" erstelle, die wahr oder falsch sein kann.
    Im diesem Query müssen zunächsteinmal die beiden Tabellen irgendwie verriegelt werden (irgendwie LOCK TABLES), damit doppelte Aufrufe des Skripts sich nicht in die Quere kommen. Dann werden aus allen vier Tabellen passende 4-Tupel an Einträgen ausgewählt:

    Code:
    SELECT * FROM ´dotaplayers´, ´gameplayers´, ´dotagames´, ´games´ WHERE ´games´.´id´ = ´dotagames´.´gameid´ AND ´games´.´id´ = ´gameplayers´.´gameid´ AND ´games´.´id´ = ´dotaplayers´.´gameid´ AND ´dotagames´.´winner´ != 0 AND ´dotagames´.´read´ = FALSE
    Habe ich das soweit richtig? Vorallem bei dem "!=" und dem "FALSE" bin ich mir nicht wirklich sicher...

    Jetzt muss ich alle obengenannten Daten unter dem entsprechenden Eintrag (Schlüssel "name") in der neuen Tabelle aktualiseren und ab jetzt habe ich keine Ahnung mehr, denke ich. Was ist zum Beispiel, wenn der Eintrag noch nicht existiert, und wie addiere ich etwas zu einem Feld wie "kills".
    Für die zusätzlichen Spalten wie "killratio" brauche ich auch noch die durchschnittliche Spieldauer, die ich aus allen Einträgen der "dotagames"-Tabelle errechnen könnte, aber wie Speichere ich mir soetwas?

    Abschließend muss ich dann noch alle Werte der Spalte "read" der gelesenen Einträge auf true setzen und die Tabellen entriegeln.

    In der Hoffnung, dass irgendjemand, der Ahnung von MySQL hat, bis zum Ende gelesen hat und sich für mein Problem interessiert

    Speedy Consoles
    Geändert von Speedy Consoles (16.12.2009 um 00:14 Uhr)

  9. #9
    König(in) Avatar von crAzywuLf
    Registriert seit
    03.02.2009
    Beiträge
    1.175
    Danke
    1
    Bekam 0 mal "Danke" in 0 Postings

    Standard AW: Paralleler Datenbankzugriff

    kannst du uns mal ein SHOW CREATE TABLE `x` von deinen Tabellen machen, weil es hört sich so an als hätte die die falsche Struktur, vielleicht kann man die ja noch optimieren und vielleicht würde dann auch das LOCK TABLE überflüssig. Den Teil mit der Spalte `read` verstehe ich nicht, wenn du das so meinst, dass es für den User als gelesen makiert werden soll, dann müsstest du das individuell speichern, weil das so sonst für alle gelten würde.
    Gruß crAzywuLf

  10. #10
    Youngster
    Themenstarter

    Registriert seit
    13.12.2009
    Beiträge
    14
    Danke
    0
    Bekam 0 mal "Danke" in 0 Postings

    Standard AW: Paralleler Datenbankzugriff

    Die Spalte "read" soll dafür da sein, damit ich nicht jedes mal die neue Tabelle neuschreibe, sondern nur um die neuen Spiele erweitere.

    Hier die Tabellen:
    games:
    Code:
    CREATE TABLE `games` (
      `id` int(11) NOT NULL auto_increment,
      `botid` int(11) NOT NULL,
      `server` varchar(100) NOT NULL,
      `map` varchar(100) NOT NULL,
      `datetime` datetime NOT NULL,
      `gamename` varchar(31) NOT NULL,
      `ownername` varchar(15) NOT NULL,
      `duration` int(11) NOT NULL,
      `gamestate` int(11) NOT NULL,
      `creatorname` varchar(15) NOT NULL,
      `creatorserver` varchar(100) NOT NULL,
      PRIMARY KEY  (`id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=latin1
    dotagames:
    Code:
    CREATE TABLE `dotagames` (
      `id` int(11) NOT NULL auto_increment,
      `botid` int(11) NOT NULL,
      `gameid` int(11) NOT NULL,
      `winner` int(11) NOT NULL,
      `min` int(11) NOT NULL,
      `sec` int(11) NOT NULL,
      PRIMARY KEY  (`id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=latin1
    gameplayers:
    Code:
    CREATE TABLE `gameplayers` (
      `id` int(11) NOT NULL auto_increment,
      `botid` int(11) NOT NULL,
      `gameid` int(11) NOT NULL,
      `name` varchar(15) NOT NULL,
      `ip` varchar(15) NOT NULL,
      `spoofed` int(11) NOT NULL,
      `reserved` int(11) NOT NULL,
      `loadingtime` int(11) NOT NULL,
      `left` int(11) NOT NULL,
      `leftreason` varchar(100) NOT NULL,
      `team` int(11) NOT NULL,
      `colour` int(11) NOT NULL,
      `spoofedrealm` varchar(100) NOT NULL,
      PRIMARY KEY  (`id`),
      KEY `gameid` (`gameid`)
      ) ENGINE=InnoDB DEFAULT CHARSET=latin1
    dotaplayers:
    Code:
    CREATE TABLE `dotaplayers` (
      `id` int(11) NOT NULL auto_increment,
      `botid` int(11) NOT NULL,
      `gameid` int(11) NOT NULL,
      `colour` int(11) NOT NULL,
      `kills` int(11) NOT NULL,
      `deaths` int(11) NOT NULL,
      `creepkills` int(11) NOT NULL,
      `creepdenies` int(11) NOT NULL,
      `assists` int(11) NOT NULL,
      `gold` int(11) NOT NULL,
      `neutralkills` int(11) NOT NULL,
      `item1` char(4) NOT NULL,
      `item2` char(4) NOT NULL,
      `item3` char(4) NOT NULL,
      `item4` char(4) NOT NULL,
      `item5` char(4) NOT NULL,
      `item6` char(4) NOT NULL,
    
      `hero` char(4) NOT NULL,
      `newcolour` int(11) NOT NULL,
      `towerkills` int(11) NOT NULL,
      `raxkills` int(11) NOT NULL,
      `courierkills` int(11) NOT NULL,
      PRIMARY KEY  (`id`),
      KEY `gameid` (`gameid`,`colour`)
      ) ENGINE=InnoDB DEFAULT CHARSET=latin1

Ähnliche Themen

  1. Datenbankzugriff auf MS SQL Server 2005
    Von keks1984 im Forum PHP Forum - Apache - CGI - Perl - JavaScript und Co.
    Antworten: 0
    Letzter Beitrag: 12.10.2007, 15:29

Stichworte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •