Я проектирую базу данных для карточной онлайн-игры с MySQL и PHP.
Я знаю, что оба они не рекомендуются для скорости онлайн-играми, но они отлично работают для моего проекта.
Я нахожусь на этапе оптимизации (игровая альфа готова и проверена на ошибки и скорость), и я обнаружил, что:
Я сделал простой тест для этого, и вот результаты:
У меня проблема с интерпретацией. Конечно, прямые вызовы PHP здесь быстрее, но действительно ли это различие имеет значение? Даже если разница в процентах очень велика, единственное, что имеет значение, — это реальное время (в с, мс) и «лаги» для игроков.
Среднее время запроса-ответа для игрового сервера составляет около 50-200ms
и это приводит к хорошему пользовательскому опыту — гладкие результаты, не заметные в карточной игре (примечание: это карточная пошаговая игра, а не шутер в реальном времени!).
Если разница во времени не важна, я предпочитаю:
$mysqli->query("SELECT add_player('".$login."', '".$password."');
над:
$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);
по соображениям безопасности и читаемости. Но скорость очень важна для моего игрового проекта, и ресурсы у меня ограничены.
Код теста (ограничение по времени выполнения для php было отключено):
<?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;
}
?>
— редактировать:
Отключение проверок внешних ключей не влияет на скорость (это дает разницу в 2-3%). Я считаю, что основной причиной более длительного времени выполнения хранимых функций MySQL является то, что (согласно этот источник):
Каждое отдельное соединение с сервером MySQL поддерживает свой собственный
кеш процедур. (…) Если ваше приложение использует хранимые процедуры, соединение компилирует хранимую процедуру, сохраняет ее в кэше и уничтожает этот кэш каждый раз, когда вы подключаетесь к серверу базы данных и запускаете оператор CALL.
Более того (тот же источник):
Каждый, кто задает этот вопрос, предполагает что-то о реализации хранимых процедур MySQL; они ошибочно полагают, что хранимые процедуры компилируются и хранятся в глобальном кэше хранимых процедур, аналогично кешу хранимых процедур в Microsoft SQL Server или Oracle. Это не верно. Вычеркнуто неверно.
Задача ещё не решена.
Других решений пока нет …