Xpoint
   [напомнить пароль]

Помогите с алгоритмом

Метки: [без меток]
2008-11-01 10:05:34 [обр] Антон[досье]

Пишу wap интерфейс раздела "Знакомств" на perl.
Пытаюсь оптимизировать свой код, и вот что имею:
Задача: вывести список Онлайн пользователи постранично (по 10, напрмер, на страницу), с возможностью выбора раздела (например, по всему сайту, только тех, кто в знакомствах, только тех, кто в дневниках и тп)
мое решение:

  1. структура бд:
  1. таблица users: id | login | passwrd (пользователи)
  2. таблица uconnected: id | razdel | unixtime (время конекта) - сюда пишу id юзера, с какого раздела конект, например news - новости читает юзер, unixtime время юниксовое+1800 сек, 1800 сек - типа жизни сессии, соответсвенно if unixtime-now(в юникс формате)>0 - юзер в онлайне
  3. таблица users_score: id | score - очки юзера, по которым собственно проводится сортировка в онлайне, очки начисляются за каждый пост юзера, обмен сообщением и тп
  4. таблица users_toppay: id | unixtime_pay - оплаченый топ, если как говорится не можешь попасть сам - заплати деньги.. unixtime_pay - время в юних формате, до которого проплачена услуга

.. структуру БД (как я вижу ее) описал, теперь собственно решение 2:

  1. Хранимые процедуры (на mysql):
  1. get_online(razdel,w,a); - замысел передать в процедуру параметры раздела, например "blogs" и w,a - соответсвующие LIMIT 0,10 в sql запросе.. собственно сама хранимая процедура:

вообщем, если сделать следующий запрос: call get_online("all",-1,-1) - выведет всех онлайн юзеров, или, call get_online("blogs",0,10) - всех юзеров, сидящих в блогах, но соответсвенно отсортированных и отлимиченных Limit 0,10

тут мне кажется оптимизировать нечего ибо хранимая процедура выполняется в среднем за 63 мс.

  1. Собствено сама реализация на перл (кусок):

   my $allcol = execute_queryV2($dbh,"call get_useronline('all',-1,-1);");
   if ($allcol!=0) {
      my $col = 10;
      my $cur = ($page-1)*$col;
      my $navigate = get_pages({
         "col" => $col,
         "allcol" => $allcol,
         "page" => $page,
         "onpage" => "3",
         "url" => "/on_line/?sid=$sid",
      });

      $content .= qq{Online \[$allcol\]};

      $content .= qq{<br/>\[стр. $$navigate[0] из $$navigate[1]\]};

      my $sth = $dbh->prepare("call get_useronline('all',$cur,$col);");
             if (!$sth) { die "Error:" . $dbh->errstr . "\n"; }
      $sth->execute();
      while (my $rst=$sth->fetchrow_arrayref()) {
      my $user_id=$$rst[0];
      my $user_score=$$rst[1];
      my $user_toppay=$$rst[2];

      $content .= qq{<br/>} . get_user_card($dbh,{
         "site" => "wap",
         "uid" => $user_id,
         "myid" => $myid,
         "sid" => $sid,
         "status_line" => 0,
         "show_city" => 1,
         "show_emotion" => 1,
         "show_whenbeen" => 0,
         "show_smile" => 0,
      });

      }
      $sth->finish();

sub get_pages {
my ($o) = @_;

   my $rand = int(rand(1000));

   my $allpage = int($$o{allcol}/$$o{col});
   $allpage++ if $$o{allcol}%$$o{col} != 0;

   my $diapcol = int($allpage/$$o{onpage});
   $diapcol++ if $allpage%$$o{onpage} != 0;

   # определяем, к какому диапазону относится страница $$o{page}
   my $diap_page = int($$o{page}/$$o{onpage});
   $diap_page++ if $$o{page}%$$o{onpage} != 0;

   if ($diap_page>$diapcol) { $diap_page = $diapcol; }
   if ($$o{page}>$allpage) { $$o{page} = $allpage; }

   my $page_str;
   my $start_diap = ($diap_page-1)*$$o{onpage}+1;
   my $stop_diap = $diap_page*$$o{onpage}; $stop_diap = $allpage if $stop_diap>$allpage;

   if ($$o{arrow} ne "no") {
      my $nav_br=0;
      if ($allpage>1 and $$o{page}!=1) { $nav_br=1; my $prev_page = $$o{page}-1; $page_str .= qq{<a href="$$o{url}\&amp;page=$prev_page\&amp;$rand">\&\#171;\&\#171;</a> }; }
      if ($allpage>1 and $$o{page}!=$allpage) { $nav_br=1; my $next_page = $$o{page}+1; $page_str .= qq{<a href="$$o{url}\&amp;page=$next_page\&amp;$rand">\&\#187;\&\#187;</a> }; }
      if ($nav_br==1) {$page_str .= qq{<br/>};}
   }

   if ($diap_page>1 and $diapcol!=1) {
      my $prev_page = $start_diap-1;
      $page_str .= qq{<a href="$$o{url}\&amp;page=1\&amp;$rand">1</a> | <a href="$$o{url}\&amp;page=$prev_page\&amp;$rand">...</a> | };
   }

   for (my $i=$start_diap;$i<=$stop_diap;$i++) {
      if ($i==$$o{page}) {
         $page_str .= qq{<b>$i</b> | };
      } else {
         $page_str .= qq{<a href="$$o{url}\&amp;page=$i\&amp;$rand">$i</a> | };
      }
   }
   $page_str =~ s/ \| $//;

   if ($diap_page<$diapcol and $diapcol!=1) {
      my $next_page = $stop_diap+1;
      $page_str .= qq{| <a href="$$o{url}\&amp;page=$next_page\&amp;$rand">...</a> | <a href="$$o{url}\&amp;page=$allpage\&amp;$rand">$allpage</a>};
   }

   my @res;
   push(@res,$$o{page});
   push(@res,$allpage);
   push(@res,$page_str);
   my $res_ref = \@res;
return $res_ref;
}

функция get_user_card выдает строку типа:

Tierno (м, 25)
Работаю
Новокузнецк
Кем обл.
инфо (5 фото)

В результате, получаю нечто такое:

Tierno (м, 25)
Работаю
Новокузнецк
Кем обл.
инфо (5 фото)


мария (ж, 17)
не в настрении
Кемерово
Кем обл.
инфо (2 фото)


...

Собственно можете предложить что нибудь по оптимизации выше перечисленного? где именно могут быть скрытые камни?

спустя 1 минуту [обр] Антон[досье]
да, кстати юза CGI::Fast
спустя 34 минуты [обр] Михаил(0/17)[досье]
  1. посоветовал бы использовать шаблонизатор, дабы разделить, представление, от логики (время выполнения, конечно чуть увеличится, но это даст большую читабельность кода, и более лёгкую расширяемость)
  2. объеденить таблицы users и users_score, и даже возможно users_toppay (если структура users_toppay такова, как Вы написали)
  3. может я гдето потерял "ниточку", но, зачем вызывать два раза подряд get_useronline ? А именно:
my $allcol = execute_queryV2($dbh,"call get_useronline('all',-1,-1);"); и my $sth = $dbh->prepare("call get_useronline('all',$cur,$col);");
спустя 19 минут [обр] Антон[досье]
  1. не понял про что вы :(
  2. Возможно в этом есть логика, вы правы, но, скажем на 10000 юзеров - toppay будет пользоваться 50, не получится ли что много данных будет просто лишними? те 9950?
  3. По крайней мере я для себя по другому задачу не решил6 суть ее в следующем:

первым запросом получить общее кол-во записей (чтобы построить кол-во страниц)
вторым собственно я получаю данные, например
таблица:
1 | gold
2 | silver
3 | bronze

надо вывести по 2 записи на страницу, а внизу ссылки на страницы:
пример:

Страница 1 из 2:
gold
silver


1 | 2

Страница 2 из 2:
bronze


1 | 2

как еще сделать я не придумал... вот и приходится делать чтото типа
$page = 1;
select count(id) from table
и
select * from table limit $page-1 , 2

спустя 7 часов [обр] Филипп Ткачев(6/112)[досье]
Идеально хранить псевдостатичную (страниц, пользователей, остальное в том же духе) информацию в отдельной таблице и обновлять при важных событиях.
Использовать кэширование запросов.
спустя 1 час [обр] Антон[досье]

еще вопрос, как оптимальнее сделать авторизацию на сайте?
Мое решение: Cgi::Session::File (правда почитал тут ваш спор про CGI - и понял, что может не стоит юзать для сессий этот модуль)
В сессии храню ЛОГИН И ПАРОЛЬ.

При каждом обращении считываю логин пароль из сессии и sql запросом (тут правда юзаю опять хранимаю процедуру), проверяю - совпадают ли логин с паролем.

Оптимальный ли вариант? или же достаточно в сессию записать статус авторизации и по нему определять авторизован ли юзер или нет?
Подскажите ваше решение или прокомментируте мое?

спустя 3 дня [обр] Алексей Севрюков(198/1280)[досье]
Антон[досье] Естественно записать статус авторизации. И если у пользователя есть ID, то и его. Незачем каждый раз производить проверку логина и пароля.
CGI::Session::File не обязательно подгружает модуль CGI. В обсуждении учавствовал только модуль CGI, но не его подмодули. CGI - это всего лишь интерфейс, и совсем не обязательно не использовать модуль, если он начинается с этих трех букв.
спустя 6 часов [обр] Thirteensmay(15/157)[досье]
Антон[досье] Оптимально или нет зависит от методов работы, и вообще механизма распределения доступа. Мы то не знаем что у вас там, это сами лучше подумайте. В простейшем случае достаточно статуса авторизации, это если распределение доступа ну совсем простое, типа авторизован - значит может. В этом случае все просто и нет лишних заморочек, что несомненно плюс. Но если распределение доступа должно быть более гибким, например один и тот же пользователь должен иметь разный по качеству доступ к разным ресурсам, то тут уже все немного сложнее, если вы не знаете на что механизм распределения доступа у вас может вылезти в перспективе, лучше сразу сделайте гибко, да собственно говоря не так уж там и много наворотов получается чтобы на них экономить, думаю всегда следует сразу рассчитывать на гибкость. А если уж так то на клиенте (лично я храню и думаю что это правильно) надо хранить только идентификатор сессии, а в сессии на сервере идентификатор пользователя. Дальше это можно раскручивать. Хранить в сессии логин и тем более пароль, чесногря помоему не разумно, зачем каждый раз проверять их соответствие ? нормально проверять доступ пользователя по его идентификатору из сессии к текущему ресурсу. И еще, пароль у нас секретная информация, ненадо хранить его где попало в разных местах.
спустя 9 часов [обр] Антон[досье]

Кстати, на данный момент у сайта неплохая посещаемость, что и потребовало модернизацию... Проводил тесты на fcgi, используя CGI::Session с хранением в БД mysql, и CGI::Session::File - хранение в файлах..

так вот, файлы намного шустрее оказались! сейчас вот думаю, ведь может все и от модуля зависеть? а какой механизм сессий используете вы?

спустя 17 часов [обр] Алексей Севрюков(198/1280)[досье]
Антон[досье] в FCGI насколько мне известно можно кэшировать дескриптор базы данных. Вы ведь в курсе что львиную часть времени занимает не работа БД, а подключение к ней? Чем меньше запросов - тем это заметнее.
P.S. Я используй свой личный механизм, использующий serialize/unserialize структур данных и хранящий данные в БД. Для меня не актуально переносить сессии в файлы потому все равно использую БД в других целях. Да и работать с файлами сложнее, чем с БД.
спустя 51 минуту [обр] Thirteensmay(15/157)[досье]
Антон[досье] Зависеть может от чего угодно, весь вопрос в конкретных условиях. Сделайте хранение в расшаренной памяти, получится еще быстрее чем в файлах, только толку, как заметил Алексей Севрюков[досье] часто мало, потому что БД всеравно используется, я бы даже сказал оно вредно, потому что система начинает расползаться по закоулкам, получается что какие-то данные мы храним в БД, какие-то в файлах, какие-то еще бог знает где. Да и методология работы с данными также усложняется, для БД один модуль, для файлов другой, для памяти третий, XML можно еще прицепить, короче бардачок'с получается. При некоторых условиях это может быть оправдано, при других нет, как я уже сказал все зависит от конкретных условий, в общем случае невозможно сказать что лучше хранить в файлах или еще гдето. По поводу а какой механизм сессий используете вы ?, я использовал куки + Методы распределения доступа
Powered by POEM™ Engine Copyright © 2002-2005