0

I am designing the database for online card game with MySQL and PHP.

I know that both of them are not the speed daemons recommended for online games, but they work fine for my project.

I am at the optimization phase (the game alpha is ready and tested for bugs and speed) and I've found that:

  • When I use MySQL stored functions and foreign keys checks I have an extra security and readability.
  • When I resign from them and use the database just as "flat" tables with records (without stored functions and foreign keys checks) I have an extra speed.

I made a simple test for it and here are the results: enter image description here enter image description here

I have a problem with the interpretation. Of course, the PHP direct calls are faster here, but does this difference really matters? Even if it's a lot as percentage difference, the real time (in s, ms) and "lags" for players is the only thing that matters.

The average request-respond time for the game server is around 50-200ms and it results in a good user experience - smooth results, not noticeable in card game (note: it's card turn-based game, not a real time shooter!).

So, should I care about those differences?

If the time difference is not important I will prefer:

$mysqli->query("SELECT add_player('".$login."', '".$password."');

over:

$mysqli->query("INSERT INTO players (login, `password`, registered, last_logged, active_deck_id) VALUES ('".$login."', '".$password."', now(), now(), 0)");
$player_id = $mysqli->insert_id;
$mysqli->query("INSERT INTO decks (`name`, player_id) VALUES (`sample deck`, ".$player_id.")");
$mysqli->query("UPDATE players SET active_deck_id = ".$mysqli->insert_id." WHERE player_id = ".$player_id);

for the security and readability reasons. But the speed is very important for my game project and the resources I have are limited.

The code of the test (the execution time limit for php was disabled):

<?php
$maxSteps = 50;
/* speed test - mysql function with foreign key restrictions vs direct calls from php */

while($maxSteps <= 5000){

    //-------------------------------------------------------------------------------

    $login = "login";
    $password = "password";

    $mysqli = new mysqli("localhost", "root", "", "fantasy_forces2"); //the database without any stored functions or foreign key restrictions
    if ($mysqli->connect_errno) {
        echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
    }

    //echo "<h1>Series of PHP direct calls to MySQL START...</h1>";
    $start = microtime(true);
    $i=0;
    while($i<$maxSteps){
        $login .= $i;
        $mysqli->query("INSERT INTO players (login, `password`, registered, last_logged, active_deck_id) VALUES ('".$login."', '".$password."', now(), now(), 0)");
        $player_id = $mysqli->insert_id;
        $mysqli->query("INSERT INTO decks (`name`, player_id) VALUES (`sample deck`, ".$player_id.")");
        $mysqli->query("UPDATE players SET active_deck_id = ".$mysqli->insert_id." WHERE player_id = ".$player_id);
        $i++;
    }
    $timeElapsed = microtime(true) - $start;
    echo "<p>Series of PHP calls ENDED after ".$timeElapsed."  seconds.</p> for ".$maxSteps." steps.";

    //-------------------------------------------------------------------------------

    $login = "login";
    $password = "password";

    $mysqli = new mysqli("localhost", "root", "", "fantasy_forces");
    if ($mysqli->connect_errno) {
        echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
    }

    //echo "<h1>MySQL procedure + foreign key restrictions START...</h1>";
    $start = microtime(true);
    $i=0;
    while($i<$maxSteps){
        $login .= $i;
        if (!$mysqli->query("SELECT add_player('".$login."', '".$password."')")) {
            echo "CALL failed: (" . $mysqli->errno . ") " . $mysqli->error;
        }
        $i++;
    }
    $timeElapsed = microtime(true) - $start;
    echo "<p>MySQL procedure ENDED after ".$timeElapsed." seconds.</p> for ".$maxSteps." steps.";

    //-------------------------------------------------------------------------------


    $maxSteps = $maxSteps * 10;
}
?>

-- edit:

Turning off the foreign keys checks does not impact on the speed (it gives 2-3% difference). I believe the main reason for a longer time of MySQL stored functions execution is that (according to this source):

Every single connection to the MySQL server maintains it’s own stored procedure cache. (...) If your application uses stored procedures, the connection is compiling the stored procedure, storing it in a cache, and destroying that cache every single time you connect to the database server and issue a CALL statement.

Moreover (the same source):

Every person that asks this question assumes something about MySQL’s stored procedure implementation; they incorrectly believe that stored procedures are compiled and stored in a global stored procedure cache, similar to the stored procedure cache in Microsoft SQL Server or Oracle. This is wrong. Flat-out incorrect.

PolGraphic
  • 3,233
  • 11
  • 51
  • 108
  • @MarcusAdams because I want restrict the user/programmer from editing the `players.active_deck_id` to e.g. not existing deck's id etc. (there are much more operations then just adding a player n that database). And when I already have a foreign keys, I don't really need a transaction here (last_instert_id etc. are per session so it's safe). In other words: foreign keys give me security in more places than just in that add_player function/procedure (also when somebody made a mistake and used single SQL query to update deck_id or when person want to delete the player with single query). – PolGraphic Feb 04 '15 at 13:22
  • @MarcusAdams about the PDO and parametrized queries - that would be a third solution, indeed. – PolGraphic Feb 04 '15 at 13:26
  • @MarcusAdams I've never wrote I don't need foreign key constraints with stored procedures. I have two scenarios: 1) database with foreign keys restrictions and with stored procedures (that does NOT need transactions because of that foreign keys and per session last_insert_id etc.). 2) database with no restrictions and procedures - theoretically unsafe, but faster. P.s. inside of the procedure I use `SET FOREIGN_KEY_CHECKS = 0` and then back to `1` (it's also per session operation on local not global flag). – PolGraphic Feb 04 '15 at 13:28

0 Answers0