Ранги пользователей: как это сделать без SQL?

Я разрабатываю серверную часть онлайн-игры, и одной из задач является вычисление рангов пользователей. На данный момент это делается с использованием СУБД, но она обновляет каждую пользовательскую строку каждый раз, когда какой-либо игрок выигрывает игру. Это приводит к тупикам сейчас, когда в среднем 20 игроков онлайн.

Я понимаю тенденцию - когда будет 1000 игроков, база данных вообще не будет работать.

Как вычислить рейтинг пользователей в реальном времени на сервере Apache/PHP? Есть ли более разумное решение для базы данных?


person Denis Kulagin    schedule 16.01.2013    source источник
comment
Взаимоблокировки при 20 пользователях? Похоже, вы используете Access. Т/Н?   -  person Sammitch    schedule 16.01.2013
comment
Нисколько. Я использую MySQL, но обновления рангов пользователей могут перекрываться, когда несколько пользователей одновременно обращаются к базе данных. Что вызывает взаимоблокировки, я считаю.   -  person Denis Kulagin    schedule 16.01.2013


Ответы (2)


Вы можете поместить свои ранги в другую таблицу, которую вы TRUNCATE каждый раз. Подобный вопрос уже задавался (и на него был дан ответ), и его можно найти здесь: Лучший способ обновить рейтинг пользователей, не убивая сервер

person Marty McVry    schedule 16.01.2013
comment
Отличное решение, спасибо. Но мне интересно, есть ли решение, которое вообще не использует СУБД? Задача легко решается с помощью сбалансированных BST, может есть что-то готовое для Apache/PHP? - person Denis Kulagin; 16.01.2013
comment
Реализован такой подход, но теперь он генерирует много повторяющихся ошибок ключа. Дело в том, что несколько пользователей могут запускать обновление ранга одновременно, что приведет к перекрытию запросов. Похоже, что решение просто превращает проблему в другую, но не решает ее. - person Denis Kulagin; 18.01.2013
comment
А как насчет подхода Саммича? - person Marty McVry; 19.01.2013

Почему вы вообще храните ранги в отдельной таблице? Сохраняйте оценки и запрашивайте ранги по мере необходимости или даже создавайте представление. Вам нужно только обновить данные, относящиеся к одному пользователю, а не обновлять всю таблицу, и если вы используете таблицы InnoDB, запросы UPDATE будут использовать блокировку на уровне строки, а не блокировку на уровне таблицы, которую вы получаете с myISAM.

TABLE users
  user_id INT PK
  user_name VARCHAR
  ...

TABLE user_scores
  user_id PK FK
  score INT INDEX
  wins INT INDEX

VIEW v_user_ranks
  SELECT u.user_id, u.user_name, s.score, s.wins
  FROM users u INNER JOIN user_scores s
    ON u.user_id = s.user_id

SELECT *
FROM v_user_ranks
ORDER BY score, wins DESC
LIMIT 10

INSERT INTO user_scores (user_id, score, wins)
  VALUES ($id, $score, $wins)
  ON DUPLICATE KEY UPDATE score=score+$score, wins=wins+$wins
person Sammitch    schedule 16.01.2013
comment
Дело в том, что мне нужно иметь возможность достаточно быстро получать рейтинг пользователя (чтобы сообщать пользователю его старый/новый рейтинг и изменять его, когда он выигрывает игру), а также иметь возможность показывать таблицу рейтинга пользователя, отсортированную не по рангу, а по какому-то другому. категория (по алфавиту, например). Вот почему мне нужно актуализировать пользовательские рейтинги каждый раз, когда они могут измениться. - person Denis Kulagin; 17.01.2013
comment
Ваш способ включает обновление полной таблицы каждый раз, когда пользователь выигрывает игру, а затем выбор X строк, упорядоченных определенным образом. Мой способ включает обновление одной строки, а затем выбор X строк в определенном порядке. Какой из них звучит быстрее? Кроме того, при выполнении операций, которые затрагивают всю таблицу так часто, вы никогда не сможете обойти тупиковые ситуации на уровне таблицы, с которыми вы боретесь прямо сейчас. - person Sammitch; 17.01.2013
comment
Извините, еще не понял ваш путь( Не могли бы вы уточнить это для меня, пожалуйста. Что такое счет и что такое победы? Где рейтинг пользователя? - person Denis Kulagin; 18.01.2013
comment
@user1065145 user1065145 поля score и wins будут хранить совокупный счет и количество побед игрока, а рейтинг будет определяться на основе индекса строки в наборе результатов. Существуют есть способы принудительного ввода фактического числа в результирующий набор, но это проще и гибче сделать в программном коде, а не в запросе. - person Sammitch; 18.01.2013
comment
Это нормально, когда вам нужно получить ранг только одного игрока за раз. Что, если вам нужно все это одновременно? - person Denis Kulagin; 19.01.2013
comment
@ user1065145 с оператором SELECT. Как в моем ответе. ಠ_ಠ - person Sammitch; 20.01.2013
comment
Что, если мне нужна рейтинговая таблица, отсортированная по имени пользователя, а также по рангам? т.е. ABC - 32 место, EEE - 234 место, XYZ - 1 место, ZZZ - 45 место и т.д. - person Denis Kulagin; 20.01.2013