[Moscow.pm] Постраничный вывод (Pagination)

Alexandr Alexeev afiskon на gmail.com
Пн Апр 23 18:46:25 PDT 2012


Я Paginator::Lite использовал, работает.

Хочу только обратить внимание на возможную проблему производительности.
Если у вас 1 млн элементов, которые вы разбиваете на 100 000 страниц по 10
элементов, то ваш сайтик может ощутимо тормозить за счет LIMIT-запросов.
Эффективнее писать "Перейти к следующей/предыдущей странице", используя для
выборки primary key или иное проиндексированное поле первого элемента
выборки. Тогда ваши запросы превращаются в быстрые SELECT ... WHERE key >=
$key LIMIT 10

Кстати, может кто-нибудь пробовал оптимизировать такие запросы? Удавалось
найти хорошее решение? Ну, например, если данные обновляются редко, можно
раз в сутки рассчитывать по крону, на какой странице какие элементы
отображать.


23 апреля 2012 г. 20:26 пользователь Alessandro Gorohovski <
angel на domashka.kiev.ua> написал:

> oleg alexeenkov <proler на gmail.com> писал(а) в своём письме Mon, 23 Apr
> 2012 19:11:11 +0300:
>
>
>  Alessandro Gorohovski <angel на domashka.kiev.ua> писал(а) в своём письме
>> Mon, 23 Apr 2012 19:58:41 +0400:
>>
>>  Andrew Shitov <andy на shitov.ru> писал(а) в своём письме Mon, 23 Apr 2012
>>> 18:49:39 +0300:
>>>
>>>  http://search.cpan.org/search?query=pagination&mode=all
>>>> ?
>>>>
>>>
>>>
> Олег,
>  Спасибо большое!
> :)
>
> Любопытный код. Буду ковыряться.
>
>
>
>
>> [вброс] давным давно наковырял такую штуку, работает с миллиардами
>> страниц 8) причем скорее всего путь перехода со страницы X на страницу Y
>> будет наименьшим среди аналогов (особенно если подкрутить параметры)
>>
>> sub gotopage {
>>   my ($fparam) = @_;
>>   my (%ret);
>>   #$fparam->{'total'} : total results, usually COUNT(*) as total
>>   #-----------size -- : size of one page in rows (LIMIT x,size)
>>   #current : current page number
>>   #actual : usually $DBI::rows, if total unknown
>>   #last : last page number (auto calculated from total/size if 0)
>>   #total_max = 1000 : maximum db results
>>   #printlog('dmp', 'gotopage start:', Dumper($fparam));
>>   $fparam->{'size'} = 100 unless defined $fparam->{'size'};
>>   return {} unless $fparam->{'size'};
>>   $fparam->{'actual'} = $fparam->{'size'} unless defined
>> $fparam->{'actual'};
>>   $fparam->{'current'} ||= 1;
>>   $fparam->{'last'} ||=
>>     $fparam->{'size'} < 1
>>     ? undef
>>     : ( int( $fparam->{'total'} / ( $fparam->{'size'} || 1 ) ) + (
>> $fparam->{'total'} % ( $fparam->{'size'} || 1 ) ? 1 : 0 ) );
>>   $fparam->{'buttonsb'} ||= $config{'gotopage_bb'} || 5;    #before
>>   $fparam->{'buttonsa'} ||= $config{'gotopage_ba'} || 5;    #after
>>   $fparam->{'align'}   = 1 unless defined $fparam->{'align'};
>>   $fparam->{'jumpten'} = 1 unless defined $fparam->{'jumpten'};
>>   $fparam->{'power'}   = 2 unless defined $fparam->{'power'};
>>   my $fromto = sub {
>>     my ($n) = @_;
>>     return (
>>       ( ( ( $n - 1 ) * $fparam->{'size'} ) + 1 ) . '-'
>>         . (
>>         ( $fparam->{'total'} and ( $fparam->{'total'} < $n *
>> $fparam->{'size'} ) ) ? $fparam->{'total'} : $n * $fparam->{'size'}
>>         )
>>     );
>>   };
>>   my $align = sub {
>>     my $a = int(shift);
>>     my $len = shift || $fparam->{'align'};
>>     substr( $a, $len, length($a) - $len ) = '0' x ( length($a) - $len )
>> if $len > 0 and length($a) > $len;
>>     return $a;
>>   };
>>   #printlog('dmp', 'gotopage calc:'," <br\n/>" .Dumper($fparam) .
>> "<br\n/>");
>>   my $next = $fparam->{'actual'} >= $fparam->{'size'};
>>   if ( ( !$fparam->{'total'} and $fparam->{'actual'} > 0 )
>>     or $fparam->{'total'} >= $fparam->{'size'}
>>     or $fparam->{'current'} > 1 )
>>   {
>>     $ret{'prev'}{ $fparam->{'current'} - 1 } = $fromto->(
>> $fparam->{'current'} - 1 ) if $fparam->{'current'} > 1;
>>     for my $n ( ( $fparam->{'current'} > $fparam->{'buttonsb'} ?
>> $fparam->{'current'} - $fparam->{'buttonsb'} : 2 )
>>       .. $fparam->{'current'} + ( $next ? $fparam->{'buttonsa'} : 0 ) )
>>     {
>>       last if $fparam->{'total'} and $n > $fparam->{'last'};
>>       last if $fparam->{'total_max'} and $n * $fparam->{'size'} >
>> $fparam->{'total_max'};
>>       ( ( !$fparam->{'total'} and $n > $fparam->{'current'} + 1 ) ? ( \%{
>> $ret{'small'} } ) : ( \%{ $ret{'big'} } ) )->{$n} =
>>         $fromto->($n);
>>     }
>>     if ( $fparam->{'jumpten'} ) {
>>       $fparam->{'jumpfrom'} ||= '1' . ( 0 x ( length(
>> $fparam->{'current'} - $fparam->{'buttonsb'} ) - 1 ) );
>>       $fparam->{'jumpto'} ||= '1' . ( 0 x length( $fparam->{'current'} +
>> $fparam->{'buttonsa'} ) );
>>       $ret{'big'}{$_} = $fromto->($_)
>>         for grep { !$fparam->{'last'} or $_ <= $fparam->{'last'} }
>>         map { '1' . ( 0 x $_ ) } 1 .. length( $fparam->{'current'} ) - 1;
>>       if ($next) {
>>         $ret{'big'}{$_} = $fromto->($_)
>>           for map { '1' . ( 0 x $_ ) } length( $fparam->{'current'} ) ..
>> length( $fparam->{'last'} ) - 1;
>>       }
>>     }
>>     $fparam->{'jumpfrom'} ||= 1;
>>     $fparam->{'jumpto'}   ||= $fparam->{'last'};
>>     #$fparam->{'jumpto'} = psmisc::min( $fparam->{'jumpto'},
>> $fparam->{'last'} );
>>     $fparam->{'jumpto'} = $fparam->{'last'} if $fparam->{'last'} <
>> $fparam->{'jumpto'};
>>     if ( $fparam->{'power'} > 1 ) {
>>       my ($n);
>>       $n = $fparam->{'current'} - $fparam->{'buttonsb'} *
>> $fparam->{'power'};
>>       for (
>>         $_ = $fparam->{'buttonsb'} ;
>>         $fparam->{'jumpfrom'} >= 1 and $n > $fparam->{'jumpfrom'} and $n
>> < $fparam->{'last'} ;
>>         $n -= ( $_ *= $fparam->{'power'} )
>>         )
>>       {
>>         $ret{'big'}{ $align->($n) } = $fromto->( $align->($n) );
>>       }
>>       $n = $fparam->{'current'} + $fparam->{'buttonsa'} *
>> $fparam->{'power'};
>>       for ( $_ = $fparam->{'buttonsa'} ; $next and $n <
>> $fparam->{'jumpto'} ; $n += ( $_ *= $fparam->{'power'} ) ) {
>>         $ret{'big'}{ $align->($n) } = $fromto->( $align->($n) );
>>       }
>>     }
>>     $ret{'big'}{ $fparam->{'last'} } = $fromto->( $fparam->{'last'} ) if
>> $fparam->{'last'} > 1 and $next;
>>     $ret{'big'}{1} ||= $fromto->(1)
>>       if ( $fparam->{'last'} > 1 or !$fparam->{'total'} )
>>       and $fparam->{'actual'} >= $fparam->{'size'};
>>     $ret{'next'}{ $fparam->{'current'} + 1 } = $fromto->(
>> $fparam->{'current'} + 1 )
>>       if $next and !$fparam->{'last'}
>>         or $fparam->{'current'} < $fparam->{'last'};
>>   }
>>   #printlog('dmp', 'gotopage ret:', Dumper(\%ret));
>>   return wantarray ? ( sort { $a <=> $b } keys %{ $ret{'big'} }, keys %{
>> $ret{'small'} } ) : \%ret;
>> }
>>
> --
> Moscow.pm mailing list
> moscow-pm на pm.org | http://moscow.pm.org
>



-- 
С уважением, Александр
Личный блог: http://eax.me/
Мой форум: http://it-talk.org/
Мой Twitter: http://twitter.com/afiskon
----------- следущая часть -----------
Вложение в формате HTML было извлечено…
URL: <http://mail.pm.org/pipermail/moscow-pm/attachments/20120424/3c7b0fb7/attachment.html>


Подробная информация о списке рассылки Moscow-pm