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
Форумы портала PHP.SU :: Версия для печати :: расчет времени проведенного онлайн
Форумы портала PHP.SU » PHP » SQL и Архитектура БД » расчет времени проведенного онлайн

Страниц (2): [1] 2 »
 

1. wmaster - 04 Декабря, 2011 - 04:57:04 - перейти к сообщению
Задача узнать и показать на графике (график это уже дело десятое) активность пользователя: в какое время был, в какое нет + соотношение онлайн/офлайн.

Есть скрипт который опрашивает статус пользователя каждый 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. Как высчитать, время онлайн или офлайн по каждому пользователю? Не пойму, как сложить эти интервалы Улыбка

Могу переделать все с нуля, просто не могу понять, как лучше реализовать, чтобы БД не распухла через месяц и в человеко понятном виде смотрелось Улыбка

Возможно где-то есть уже похожее, я бы поковырялся.
2. Panoptik - 04 Декабря, 2011 - 10:06:09 - перейти к сообщению
заводишь в базе поля: время входа и последнее время с активностью. как только пользователь вошел - назначаешь ему время входа. и время активности - время входа + интервал опроса. если во время опроса пользователь в оффлайн, то вот разница между временем и будет временем в онлайне в пределах текущей сессии. а если в онлайне, то апдейтишь время активности на +интервал и получаешь на выходе чистую запись для одной сессии где время начала остается постоянным и время конца - последнее время апдейта
3. DlTA - 04 Декабря, 2011 - 10:21:21 - перейти к сообщению
весь вопрос в дискретизации, в данном случае подойдет метод записи в базу интервалов, например, время когда зашел и сколько пробыл, главное чтоб интервалы не пересикались

в таком случае можно будет легко посчитать сколько всего пробыл
и график строить просто
4. tuareg - 04 Декабря, 2011 - 11:22:00 - перейти к сообщению
Здравствуйте.
Я так вот на вскидку. Сделал бы так
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
5. wmaster - 05 Декабря, 2011 - 19:46:44 - перейти к сообщению
tuareg, пошел вашим путем. Сделал так.

таблица
u111: date (timestamp), duration (tinyint) // дата и время проведенное в онлайн в минутах, уже посчитаное.

u111_temp: date (timestamp), status (tinyint) // дата и статус онлай, пишем если пользователь в сети.


1. Скриптом, каждый 5 минут собираем статусы по u111 пользователям, пишем в u111_temp (12*24 = 288 записей в сутки на пользователя).
2. SQL запросом выбираем из таблицы u111_temp данные по активности, суммируем количество "онлайнов" и группируем по часам, иногда проще показать сам запрос, чем описывать как он работает:

CODE (SQL):
скопировать код в буфер обмена
  1. SELECT DATE_FORMAT(date,'%d %b %Hh') AS hours, SUM(STATUS) * 5 AS duration FROM u111_temp GROUP BY `hours`

3. В таблицу u111 переносим почасовую активность (то, что получили в прошлом запросе).
4. Очищаем таблицу u111_temp (можно раз в сутки, можно еще как-то, пока не придумал, как лучше)


Думаю, что такой способ разгрузит БД по нескольким причинам:
1. Экономия записей на каждом пользователе (24 в сутки)
2. Запись только "онлайна" во "временную" таблицу снижает количество обращений (если бы я писал еще и оффлайны)
3. Удобная структура таблицы u111, для отображения статистики.

Проблема

Можно ли сделать шаг 2 и 3 (а может и 4) одним SQL запросом? Типа так:
CODE (SQL):
скопировать код в буфер обмена
  1. INSERT INTO u111 (hours, duration) SELECT DATE_FORMAT(date,'%d %b %Hh') AS hours, (count(*) * 5) AS duration FROM u111_temp GROUP BY `hours`


В данном случае будет ошибка, потому что формат даты не совпадает, а мне бы хотелось всё и везде хранить в timestamp

Структура таблиц:
Спойлер (Отобразить)

Спойлер (Отобразить)
6. tuareg - 06 Декабря, 2011 - 00:44:28 - перейти к сообщению
Я рад что пошли моим путем Улыбка .
Напишите запрос как Вы сохраняете user в u111_temp? Я пока не понимаю, что за поле STATUS???
Просто в первом посте Вы указали, что надо каждого user-а, а сейчас я понимаю уже сумму всех user-ов на сайте?
Если да, то тогда вообще все еще проще можно сделать и будет у вас всего кол-во записей в таблице равное количеству интервалов.
7. wmaster - 06 Декабря, 2011 - 01:47:12 - перейти к сообщению
tuareg пишет:
Я рад что пошли моим путем Улыбка .
Напишите запрос как Вы сохраняете user в u111_temp? Я пока не понимаю, что за поле STATUS???
Просто в первом посте Вы указали, что надо каждого user-а, а сейчас я понимаю уже сумму всех user-ов на сайте?
Если да, то тогда вообще все еще проще можно сделать и будет у вас всего кол-во записей в таблице равное количеству интервалов.


1. Как я и писал, нужно для каждого отдельно вести статистику. (кол-во минут в день и соответственно кол-во часов в сутки, ну и тд.) Со времени первого поста я немного переделал структуру таблицы и логику скрипта, который опрашивает пользователей.

2. поле Status хранит единичку, если пользователь онлайн, если офф - то в базу ничего не пишет.

Запрос в таблицу u111_temp, допустим, пользователь на момент проверки онлайн:

CODE (SQL):
скопировать код в буфер обмена
  1. INSERT INTO `u111_temp` (date,STATUS) VALUES ($date, 1);


В общем-то я могу все действия делать тремя запросами, просто интересно, можно ли объединить запросы так как я спрашивал выше.

P.S. Теперь ищу удобное средство, чтобы графики рисовать Улыбка
8. tuareg - 06 Декабря, 2011 - 02:28:38 - перейти к сообщению
Может я тогда, что-то недопонимаю. Улыбка Итак:
время 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???
9. wmaster - 06 Декабря, 2011 - 12:24:50 - перейти к сообщению
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. Да не суть, даже простых посетителей форума можно "считать" так же, по нику, например.
10. wmaster - 06 Декабря, 2011 - 16:25:09 - перейти к сообщению
Я кажется нашел то, что хотел. Одним запросом я делаю выборку по временной таблице u$UID_temp, и посчитанные значения уже пишу в u$UID

CODE (SQL):
скопировать код в буфер обмена
  1. INSERT INTO $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' GROUP BY `hours`
11. tuareg - 06 Декабря, 2011 - 19:43:44 - перейти к сообщению
Это какой-то не хороший путь ... Если User будет 300 и > ???
Надо делать одну таблицу с временем а уже потом оттуда все дергать. Пока не поздно откажитесь от Вашего варианта Улыбка

Да и еще если идти таким путем, то можно просто записывать время без статуса зачем он нужен???
Но не то это все
12. wmaster - 06 Декабря, 2011 - 21:50:02 - перейти к сообщению
Возможно вы правы, только у меня пользователей не больше 100 и потом, более эффективного решения я пока не вижу.
13. tuareg - 06 Декабря, 2011 - 22:29:26 - перейти к сообщению
Я же Вам его обрисовал(решение)??? Делайте одну таблицу на сутки, в нее записывайте время и id пользователя. А потом уже выбирайте из нее все что надо.
Я не вижу какие могут быть проблемы
14. wmaster - 06 Декабря, 2011 - 23:45:47 - перейти к сообщению
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

так?

как тогда правильно выбрать нужных мне пользователей, чтобы в результирующую писать?
15. tuareg - 07 Декабря, 2011 - 00:07:40 - перейти к сообщению
Здравствуйте.
Структура следующая:
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
Вот так. тогда запрос по пользователям:
CODE (SQL):
скопировать код в буфер обмена
  1.  
  2. SELECT COUNT(*)*5 AS duration FROM `temp_table` GROUP BY `user`
  3.  

То что записей получится много (1200 при 100 активных круглосуточно не страшно, главное очищайте ее каждый день)
Да и еще смотрите если Вы будете делать SELECT всей таблицы типа
CODE (SQL):
скопировать код в буфер обмена
  1.  
  2. INSERT INTO $tbl (date, duration) SELECT DATE_FORMAT(date,'%Y-%m-%d %H') AS hours ...
  3.  

Тогда индексы вообще не нужны.
P.S Меня мучает такой вопрос уже 2 дня мучает Улыбка А как Вы график строить будете???
Ось ox-->время, а oy-->???

 

Powered by ExBB FM 1.0 RC1