#php #mysql #optimization
#php #mysql #оптимизация
Вопрос:
Я владелец онлайн-браузерной игры, в которой зарегистрировано около 300 игроков. Я написал скрипт для обнаружения читеров, но проблема в том, что количество запросов в указанном скрипте будет расти экспоненциально.
Это работает следующим образом:
- Отправьте запрос, который получит информацию об игроке.
- Внутри запроса запустите другой запрос, который получит информацию о каждом игроке.
Итак, в основном я запускаю запрос, который получает имя и информацию каждого игрока, и внутри этого запроса я запускаю другой запрос, чтобы получить информацию от всех других игроков, кроме них самих. Я использую это для сравнения и удаления читеров.
Проблема в том, что, поскольку у меня 300 игроков, я должен запускать 300 запросов на каждого игрока. Это 90 000 запросов. Если я достигну 1000 игроков, это будет 1 000 000 запросов. Должен быть лучший способ сделать это.
Мой код:
<?php
require '../connect.php';
$rulerinfo = $conn->query("SELECT id, rulername, nationname, alliance, email, dateregister, user_agent, lastseen, password FROM players");
while ($rulerinfo2 = $rulerinfo->fetch_assoc()) {
$id = $rulerinfo2['id'];
$rulername = $rulerinfo2['rulername'];
$nationname = $rulerinfo2['nationname'];
$alliance = $rulerinfo2['alliance'];
$email = $rulerinfo2['email'];
$dateregister = $rulerinfo2['dateregister'];
$useragent = $rulerinfo2['user_agent'];
$lastseen = $rulerinfo2['lastseen'];
$password = $rulerinfo2['password'];
$playerinfo = $conn->query("SELECT id, rulername, nationname, alliance, email, dateregister, user_agent, lastseen, password FROM players WHERE id != '$id'");
while ($playerinfo2 = $playerinfo->fetch_assoc()) {
$id2 = $playerinfo2['id'];
$rulername2 = $playerinfo2['rulername'];
$nationname2 = $playerinfo2['nationname'];
$alliance2 = $playerinfo2['alliance'];
$email2 = $playerinfo2['email'];
$dateregister2 = $playerinfo2['dateregister'];
$useragent2 = $playerinfo2['user_agent'];
$lastseen2 = $playerinfo2['lastseen'];
$password2 = $playerinfo2['password'];
$rulerdistance = levenshtein($rulername, $rulername2);
$nationdistance = levenshtein($nationname, $nationname2);
$emaildistance = levenshtein($email, $email2);
$agentdistance = levenshtein($useragent, $useragent2) / 2;
$totaldistance = $rulerdistance $nationdistance $emaildistance $agentdistance;
if ($password == $password2) {
$totaldistance = $totaldistance - 20;
}
if ($totaldistance < 0) {
$totaldistance = 0;
}
}
}
?>
Комментарии:
1. Показать структуры таблиц и индексы, а также результат ПОЯСНЕНИЯ к запросу
2. @MarkBaker Можете ли вы объяснить, что такое EXPLAIN?
3. ОБЪЯСНИТЕ SELECT * FROM ….. это дает много информации о таблицах, ключах и о том, как запрос объединяет (не mysql join) вещи вместе. Поэтому в основном просто ставьте «EXPLAIN» перед вашим запросом.
4. Хорошо, я попробовал, но ничего не появляется. @brechmos
5. Похоже, что вы получаете все строки
players
в памяти, затем снова выполняете запрос одну за другой. Это 1 300 запросов, так что не совсем те 300 ^ 2, о которых вы упомянули (если только я чего-то не вижу). Почему бы не загрузить их все в память, и тогда вы сможете сравнивать все со всеми намного быстрее? Это один запрос. Более того, вы можете сделать это в автономном режиме на cron, так что вы можете увеличить лимиты памяти, необходимые для большего числа пользователей.
Ответ №1:
Вы должны выполнить запрос только один раз, поместить его в массив и работать с ним оттуда. Я не вижу необходимости выполнять почти один и тот же запрос дважды. Повторите цикл в вашем массиве во второй раз и просто проверьте, не совпадает ли идентификатор с текущим.
$res = $conn->query("SELECT id, rulername, nationname, alliance, email, dateregister, user_agent, lastseen, password FROM players");
$array=array();
while ($row = $res->fetch_assoc()) {
$array[] = $row;
}
for($i=0; $i<count($array);$i ) {
for($j=0; $j<count($array); $j ) {
if ($i != $j) {
// Call your functions
$rulerdistance = levenshtein($array[$i]['rulername'], $array[$j]['rulername']);
...
}
}
}
Комментарии:
1. Спасибо! Это должно очень помочь. Я протестирую это и посмотрю, смогу ли я заставить это работать.
2. Это сработало как по волшебству. Я потратил часы на поиск того, как использовать массивы в запросах, подобных этому, но безуспешно. Ты лучший, @Johnny Drew
3.
$rulerinfo
и$rulerinfo2
не являются идеальными именами. Один из них является ресурсом результата, а другой — строкой, поэтому$result
и$row
могут быть лучше (и обычно используются). В любом случае 1.4. @halfer действительно, я просто сохранил текущий код, но внесу изменения.