Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757
Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737 Форумы портала PHP.SU :: расчет времени проведенного онлайн
Покинул форум
Сообщений всего: 14
Дата рег-ции: Дек. 2011
Помог: 0 раз(а)
Задача узнать и показать на графике (график это уже дело десятое) активность пользователя: в какое время был, в какое нет + соотношение онлайн/офлайн.
Есть скрипт который опрашивает статус пользователя каждый 5-10 минут, в сети он или нет. Если в сети - 1, нет - 0. Скрипт простой и по необходимости можно внести логику.
база состоит из таблиц с именами пользователей: u1, u2...
структура таблицы:
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`status` tinyint(4) NOT NULL
Проблемы:
1. Тупо собирать 1 и 0 очень накладно. На одного пользователя выходит порядка 300 строк в сутки. Поэтому можно немного хитрить. Допустим в 12:00 user1 online, пишем в БД (1), а в 15:30 ему валить пора, тогда и пишем в базу новую строку (0). Более экономично, даже если user1 будет часто туда-сюда "бегать".
2. Как высчитать, время онлайн или офлайн по каждому пользователю? Не пойму, как сложить эти интервалы
Могу переделать все с нуля, просто не могу понять, как лучше реализовать, чтобы БД не распухла через месяц и в человеко понятном виде смотрелось
Возможно где-то есть уже похожее, я бы поковырялся.
Panoptik
Отправлено: 04 Декабря, 2011 - 10:06:09
Постоянный участник
Покинул форум
Сообщений всего: 2493
Дата рег-ции: Нояб. 2011 Откуда: Одесса, Украина
Помог: 131 раз(а)
заводишь в базе поля: время входа и последнее время с активностью. как только пользователь вошел - назначаешь ему время входа. и время активности - время входа + интервал опроса. если во время опроса пользователь в оффлайн, то вот разница между временем и будет временем в онлайне в пределах текущей сессии. а если в онлайне, то апдейтишь время активности на +интервал и получаешь на выходе чистую запись для одной сессии где время начала остается постоянным и время конца - последнее время апдейта
----- Just do it
DlTA
Отправлено: 04 Декабря, 2011 - 10:21:21
Постоянный участник
Покинул форум
Сообщений всего: 2952
Дата рег-ции: Окт. 2010
Помог: 53 раз(а)
весь вопрос в дискретизации, в данном случае подойдет метод записи в базу интервалов, например, время когда зашел и сколько пробыл, главное чтоб интервалы не пересикались
в таком случае можно будет легко посчитать сколько всего пробыл
и график строить просто
tuareg
Отправлено: 04 Декабря, 2011 - 11:22:00
Участник
Покинул форум
Сообщений всего: 1234
Дата рег-ции: Июнь 2010
Помог: 69 раз(а)
Здравствуйте.
Я так вот на вскидку. Сделал бы так
1.Первая таблица с полями `time`(время HH:MM),`user`,`status` ENUM('yes','no')==>допустим STAT_DAY
2.Создать вторую таблицу и в ней уже хранить результирующие данные из первой таблицы
==>допустим STAT_Poln
Тогда логика следующая:
В 00:00 каждого дня по крону запускать скрипт или процедуру, которая будет собирать данные из первой таблицы(STAT_DAY) и заносить ее во вторую(STAT_Poln) и очищать первую.
Плюсы данного подхода простой запрос для внесения в первую таблицу, кстати можно посмотреть и сделать ее тип MEMORY.(Работают быстро, если превысят объем то будет как MyISAM (это так на вскидку))
P.S можно записывать только активных юзеров.
Пример время 12:00 активны юзеры 1,2,3 их записываем в Бд. Время 12:10 активны 1,3, а юзер 2 вышел тогда записываем 1,3
При таком подходе из таблицы STAT_DAY можно убрать поле status
На счет запросов сейчас еще подумаю
добавление
Если делать запрос через равный интервал(5 мин), то количество времени OnLine посчитаем простым COUNT(*), который умножим на 5 минут и получим время юзера OnLine
Покинул форум
Сообщений всего: 14
Дата рег-ции: Дек. 2011
Помог: 0 раз(а)
tuareg, пошел вашим путем. Сделал так.
таблица u111: date (timestamp), duration (tinyint) // дата и время проведенное в онлайн в минутах, уже посчитаное.
u111_temp: date (timestamp), status (tinyint) // дата и статус онлай, пишем если пользователь в сети.
1. Скриптом, каждый 5 минут собираем статусы по u111 пользователям, пишем в u111_temp (12*24 = 288 записей в сутки на пользователя).
2. SQL запросом выбираем из таблицы u111_temp данные по активности, суммируем количество "онлайнов" и группируем по часам, иногда проще показать сам запрос, чем описывать как он работает:
SELECT DATE_FORMAT(date,'%d %b %Hh')AS hours, SUM(STATUS)* 5 AS duration FROM u111_temp GROUPBY`hours`
3. В таблицу u111 переносим почасовую активность (то, что получили в прошлом запросе).
4. Очищаем таблицу u111_temp (можно раз в сутки, можно еще как-то, пока не придумал, как лучше)
Думаю, что такой способ разгрузит БД по нескольким причинам:
1. Экономия записей на каждом пользователе (24 в сутки)
2. Запись только "онлайна" во "временную" таблицу снижает количество обращений (если бы я писал еще и оффлайны)
3. Удобная структура таблицы u111, для отображения статистики.
Проблема
Можно ли сделать шаг 2 и 3 (а может и 4) одним SQL запросом? Типа так:
Покинул форум
Сообщений всего: 1234
Дата рег-ции: Июнь 2010
Помог: 69 раз(а)
Я рад что пошли моим путем .
Напишите запрос как Вы сохраняете user в u111_temp? Я пока не понимаю, что за поле STATUS???
Просто в первом посте Вы указали, что надо каждого user-а, а сейчас я понимаю уже сумму всех user-ов на сайте?
Если да, то тогда вообще все еще проще можно сделать и будет у вас всего кол-во записей в таблице равное количеству интервалов.
Покинул форум
Сообщений всего: 14
Дата рег-ции: Дек. 2011
Помог: 0 раз(а)
tuareg пишет:
Я рад что пошли моим путем .
Напишите запрос как Вы сохраняете user в u111_temp? Я пока не понимаю, что за поле STATUS???
Просто в первом посте Вы указали, что надо каждого user-а, а сейчас я понимаю уже сумму всех user-ов на сайте?
Если да, то тогда вообще все еще проще можно сделать и будет у вас всего кол-во записей в таблице равное количеству интервалов.
1. Как я и писал, нужно для каждого отдельно вести статистику. (кол-во минут в день и соответственно кол-во часов в сутки, ну и тд.) Со времени первого поста я немного переделал структуру таблицы и логику скрипта, который опрашивает пользователей.
2. поле Status хранит единичку, если пользователь онлайн, если офф - то в базу ничего не пишет.
Запрос в таблицу u111_temp, допустим, пользователь на момент проверки онлайн:
В общем-то я могу все действия делать тремя запросами, просто интересно, можно ли объединить запросы так как я спрашивал выше.
P.S. Теперь ищу удобное средство, чтобы графики рисовать
tuareg
Отправлено: 06 Декабря, 2011 - 02:28:38
Участник
Покинул форум
Сообщений всего: 1234
Дата рег-ции: Июнь 2010
Помог: 69 раз(а)
Может я тогда, что-то недопонимаю. Итак:
время 12:00 у нас 5 активных user(их id==>1,2,3,4,5)
Если нам надо по сайту сколько user---> INSERT INTO .... (время, 5) Не надо ставить 1.
Т.е всего одна запись, в которой уже все сосчитано, но тут мы не сможем вывести статистику на конкретного user
По конкретному user я предлагал INSERT ... VALUES ('12:00',1),('12:00',2),('12:00',3),('12:00',4),('12:00',5)
Поле таблицы на день зачем timestamp? Есть формат time(чч.мм.сс) более оптимально ИМХО, а в дату уже потом конвертировать при сохранении в основную таблицу.
P.S Просто я не могу понять как Вы определяете что именно я был на Вашем сайте в 12:00, а не Пупкин?
Либо у Вас еще какая-то таблица используется???
Т.е в 12:00 стоит 1 и как Вы определяет кто этот 1???
wmaster
Отправлено: 06 Декабря, 2011 - 12:24:50
Новичок
Покинул форум
Сообщений всего: 14
Дата рег-ции: Дек. 2011
Помог: 0 раз(а)
tuareg пишет:
Может я тогда, что-то недопонимаю. Итак:
время 12:00 у нас 5 активных user(их id==>1,2,3,4,5)
Если нам надо по сайту сколько user---> INSERT INTO .... (время, 5) Не надо ставить 1.
Т.е всего одна запись, в которой уже все сосчитано, но тут мы не сможем вывести статистику на конкретного user
По конкретному user я предлагал INSERT ... VALUES ('12:00',1),('12:00',2),('12:00',3),('12:00',4),('12:00',5)
Поле таблицы на день зачем timestamp? Есть формат time(чч.мм.сс) более оптимально ИМХО, а в дату уже потом конвертировать при сохранении в основную таблицу.
P.S Просто я не могу понять как Вы определяете что именно я был на Вашем сайте в 12:00, а не Пупкин?
Либо у Вас еще какая-то таблица используется???
Т.е в 12:00 стоит 1 и как Вы определяет кто этот 1???
я наверное вас запутал еще в первых постах
Суть в том, что таблицы u111 и u111_temp - таблицы пользователя 111, для 222 будет соответственно u222 и u222_temp
Скрипт опрашивает онлайн статусы моих друзей Вконтакте, через API. Да не суть, даже простых посетителей форума можно "считать" так же, по нику, например.
wmaster
Отправлено: 06 Декабря, 2011 - 16:25:09
Новичок
Покинул форум
Сообщений всего: 14
Дата рег-ции: Дек. 2011
Помог: 0 раз(а)
Я кажется нашел то, что хотел. Одним запросом я делаю выборку по временной таблице u$UID_temp, и посчитанные значения уже пишу в u$UID
INSERTINTO $tbl (date, duration)SELECT DATE_FORMAT(date,'%Y-%m-%d %H')AS hours, SUM(STATUS)* 5 AS duration FROM $tbl_temp WHERE date BETWEEN'$start'AND'$end'GROUPBY`hours`
tuareg
Отправлено: 06 Декабря, 2011 - 19:43:44
Участник
Покинул форум
Сообщений всего: 1234
Дата рег-ции: Июнь 2010
Помог: 69 раз(а)
Это какой-то не хороший путь ... Если User будет 300 и > ???
Надо делать одну таблицу с временем а уже потом оттуда все дергать. Пока не поздно откажитесь от Вашего варианта
Да и еще если идти таким путем, то можно просто записывать время без статуса зачем он нужен???
Но не то это все
Покинул форум
Сообщений всего: 14
Дата рег-ции: Дек. 2011
Помог: 0 раз(а)
Возможно вы правы, только у меня пользователей не больше 100 и потом, более эффективного решения я пока не вижу.
tuareg
Отправлено: 06 Декабря, 2011 - 22:29:26
Участник
Покинул форум
Сообщений всего: 1234
Дата рег-ции: Июнь 2010
Помог: 69 раз(а)
Я же Вам его обрисовал(решение)??? Делайте одну таблицу на сутки, в нее записывайте время и id пользователя. А потом уже выбирайте из нее все что надо.
Я не вижу какие могут быть проблемы
wmaster
Отправлено: 06 Декабря, 2011 - 23:45:47
Новичок
Покинул форум
Сообщений всего: 14
Дата рег-ции: Дек. 2011
Помог: 0 раз(а)
tuareg пишет:
Здравствуйте.
Я так вот на вскидку. Сделал бы так
1.Первая таблица с полями `time`(время HH:MM),`user`,`status` ENUM('yes','no')==>допустим STAT_DAY
2.Создать вторую таблицу и в ней уже хранить результирующие данные из первой таблицы
==>допустим STAT_Poln
Тогда логика следующая:
В 00:00 каждого дня по крону запускать скрипт или процедуру, которая будет собирать данные из первой таблицы(STAT_DAY) и заносить ее во вторую(STAT_Poln) и очищать первую.
Плюсы данного подхода простой запрос для внесения в первую таблицу, кстати можно посмотреть и сделать ее тип MEMORY.(Работают быстро, если превысят объем то будет как MyISAM (это так на вскидку))
P.S можно записывать только активных юзеров.
Пример время 12:00 активны юзеры 1,2,3 их записываем в Бд. Время 12:10 активны 1,3, а юзер 2 вышел тогда записываем 1,3
При таком подходе из таблицы STAT_DAY можно убрать поле status
На счет запросов сейчас еще подумаю
добавление
Если делать запрос через равный интервал(5 мин), то количество времени OnLine посчитаем простым COUNT(*), который умножим на 5 минут и получим время юзера OnLine
Башка уже не варит) Какая структура тогда будет у результирующей таблицы?
user, time, duration
а во временную я пишу что-то типа
time user
0:00 111
1:00 111,222
2:00 111,222
3:00 111,222,333
4:00 111
5:00 111
6:00 вообще пропустить
7:00 222
8:00 222
9:00 111,222
так?
как тогда правильно выбрать нужных мне пользователей, чтобы в результирующую писать?
tuareg
Отправлено: 07 Декабря, 2011 - 00:07:40
Участник
Покинул форум
Сообщений всего: 1234
Дата рег-ции: Июнь 2010
Помог: 69 раз(а)
Здравствуйте.
Структура следующая:
time user
0:00 111
1:00 111
1:00 222
2:00 111
2:00 222
3:00 111
3:00 222
3:00 333
Вот так. тогда запрос по пользователям:
SELECT COUNT(*)*5 AS duration FROM`temp_table`GROUPBY`user`
То что записей получится много (1200 при 100 активных круглосуточно не страшно, главное очищайте ее каждый день)
Да и еще смотрите если Вы будете делать SELECT всей таблицы типа
Все гости форума могут просматривать этот раздел. Только зарегистрированные пользователи могут создавать новые темы в этом разделе. Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.