PDA

Просмотр полной версии : [Вопрос] Статистика онлайна за N дней



123
04.11.2018, 09:25
Конечно же, рано или поздно встает вопрос о контроле посещаемости у администрации, у лидеров, и других ключевых персонажей RP сервера. Так вот, как же это реализовать?

Видел в слитых исходниках одного из проектов пример черновой реализации этой функции за неделю. Там все до безобразия просто - 7 полей в таблице у игрока, и с помощью определения дня недели онлайн сохранялся в нужное поле. В начале следующей недели - обнуление всех полей.

Пример конечно рабочий, но, как мне кажется, неправильный. Его нельзя расширить (вдруг мне понадобится статистика за месяц?), да и нагромождение виде 7 лишних полей - далеко не лучший вариант.

На ум приходит второй, более "правильный" со всех аспектов вариант.

Создать таблицу stats с полями -
id
user
enter_game - время авторизации
left_game - время выхода

И методом простого расчета left_game - enter_game - получаем время игры за одну игровую сессию.
Но встает ряд сложностей в плане реализации.

Например, мне нужно получить онлайн за последние 7 дней. Как составить такой запрос?
Допустим, я составил правильный запрос и получил данные. Теперь нужно как-то склеить все игровые сессии за каждый день и вывести в диалог по шаблону:

(дата) - (время в игре)

На что у меня тоже нет никаких мыслей.

Может кто нибудь сталкивался, и знает как это все решается?

Kucklovod00
04.11.2018, 18:39
Лучше создать отдельную таблицу и выводить результат по идентификатору/нику игрока. Если результатов будет более, чем 7 (или 30), то лишние строки удаляем. Думаю, в отдельной таблице лучше хранить статистику посещения только лидеров и администраторов, а для игроков либо не хранить, либо хранить в переменных на игрока.

Запрос для вывода статистики - SELECT. INSERT - если за сегодняшний день записи нет и UPDATE если игрок зашел более одного раза и проиграл какое-то время

DeimoS
04.11.2018, 22:23
Всё зависит от того, сколько дней ты хочешь логировать и какие критерии для логирования у тебя есть (исключать ли время в АФК и т.п.). Под каждый случай стоит выбирать свой алгоритм, который будет потреблять минимум ресурсов и давать большую скорость при выборке данных. Иначе всё может кончиться не очень хорошо.



да и нагромождение виде 7 лишних полей - далеко не лучший вариант.

Нет никакого "нагромождения" от того, что у тебя будет 7 "лишних" полей. Наоборот, в результате у тебя в таблице будет, как минимум, на 6 записей меньше для каждого из админов. Соответственно, скорость работы с данными будет выше, так как MySQL будет быстрее находить (или не находить) нужные строки. Для MySQL нормой являются таблицы и с нескольким десятком столбцов, и с сотней. Главное, чтоб это было оправдано твоими нуждами и на деле не было так, что есть более оптимальный вариант с 3-мя столбцами вместо 150-и.



На ум приходит второй, более "правильный" со всех аспектов вариант.

Создать таблицу stats с полями -
id
user
enter_game - время авторизации
left_game - время выхода

И методом простого расчета left_game - enter_game - получаем время игры за одну игровую сессию.
Но встает ряд сложностей в плане реализации.

Например, мне нужно получить онлайн за последние 7 дней. Как составить такой запрос?
Допустим, я составил правильный запрос и получил данные. Теперь нужно как-то склеить все игровые сессии за каждый день и вывести в диалог по шаблону:

(дата) - (время в игре)

На что у меня тоже нет никаких мыслей.

Как-то так

SELECT user, enter_time, IF(left_game > 0, (left_game-enter_game), (NOW()-enter_game)) AS online_time FROM table_name
Вернёт время сессии в секундах (возможно, понадобится сделать дополнительную обёртку в UNIX_TIMESTAMP для полей "left_game" и "enter_game" при вычислении). Условие "IF" там нужно для того, чтоб на случай, если в момент обращения к таблице, какой-то из админов был в сети, то для него вывело бы время текущей сессии, а не белиберду. Можно вместо "IF" сделать условие для выборки в WHERE, исключая такие записи. Так же можно сделать статистику за все дни (просто не удалять записи), но тогда лучше создать вторую таблицу, в которую раз в n-дней (например, раз в неделю/месяц или просто когда в таблице будет определённое число записей) переносить более старые записи, дабы количество столбцов не влияло ни на время выборки, ни на время обновления данных (вторую таблицу можно так же, со временем, поделить ещё на определённое количество таблиц. Или просто чистить уж очень старые записи). Так же можно объединить твой первый вариант (с n-числом полей под определённый день) и второй, просто создавая новую строку, когда все столбцы заполнятся, а не перезаписывая старые столбцы (только тогда нужно продумать алгоритм хороший для контроля даты. Например, один столбец выделить под дату первого столбца с временем онлайна. А потом сверять текущую дату с тем столбцом и если, например, с момента создания строки прошло 3 дня, а ты записывал информацию всего в первый день (2-ой столбец онлайна содержит нуль), то так же создаёшь новую строку и пишешь информацию туда, а прошлая строка пусть с нулями будет).

Ну а вообще, вот эти функции тебе в помощь - http://www.mysql.ru/docs/man/Date_and_time_functions.html. Например, если нужно отсортировать все данные за текущий месяц, а у тебя нет соответствующего столбца (ты хранишь только дату), можно сделать так:

... WHERE DATE_FORMAT(столбец_с_датой, '%m.%Y') = '11.2018'
и ты получишь нужные данные.

123
05.11.2018, 03:55
Думаю, в отдельной таблице лучше хранить статистику посещения только лидеров и администраторов, а для игроков либо не хранить, либо хранить в переменных на игрока.

Почему? Таблица для того и создается, что бы не нагромождать основную таблицу, и увеличить её отзывчивость. И если и вести такую статистику - то вести её для всех, тогда будет намного проще отбирать кандидатов на тоже лидерство или администрирование. А таблицу чистить раз в месяц или неделю, по потребности.



SELECT user, enter_time, IF(left_game > 0, (left_game-enter_game), (NOW()-enter_game)) AS online_time FROM table_name

Хорошо, с этим понятно. Прежде всего, меня интересует как отсортировать этот запрос и получать результат на каждый день из нужного периода (поскольку сейчас, записывается каждая игровая сессия, а их за один день может быть > 1. Их нужно как-то склеить).

DeimoS
05.11.2018, 04:41
SUM?


SELECT SUM(left_game-enter_game) AS online_time FROM table_name WHERE user = '123' AND DATE_FORMAT(enter_game, '%d.%m.%Y') = '05.11.2018'
Покажет сколько ты отыграл за сегодня

Хотя если тебе не нужна подробная статистика, то проще каждый день создавать 1 поле и к столбцу с онлайном прибавлять значение.
То бишь:

id | account_id | date | online_uptime
При авторизации записываешь gettime() в переменную. При выходе (а заодно и каждые 5-10 минут, дабы не потерять статистику в случае вылета сервера) делаешь запрос в базу, проверяя существования строки для игрока с сегодняшней датой, возвращая ID строки, если она найдена.
Если найдено:

UPDATE table SET online_uptime = online_uptime+/*gettime()-время_из_переменной*/ WHERE id = /*возвращённый_ID*/
Если не найден - создаёшь новую запись.

Такой вариант гораздо практичнее будет в твоём случае.