Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > аспекты работы DBD


Автор: yorm 12.6.2008, 16:41
Подскажите, пожалуйста

я делаю запрос в postgres через DBD

Код

...
$sth = $dbh->execute($blah);
while (my $row = $sth->fetchrow_arrayref()) {
    # some calculations
}


я так понимаю, что возврат уже инкапсулирован в sth?
а можно ли как-то ограничить возврат?

т.е. если возвращается, например 1000 записей, выбрать сначала 100, потом еще и еще (реальная база имеет около десятка миллиардов записей). Чтобы не хранить все в памяти?
или такое невозможно и придется пользовать лимит в запросе?

и можно ли как-то оптимизировать выборку возврата, чтобы работала побыстрее и занимала поменьше памяти? (т.е не через SQL оптимизировать, а именно алгоритм выборки)

Автор: tolkien 12.6.2008, 17:50
Использовать другой метод. Например bind_columns

my $sth = $dbh->prepare($sql);
$sth->execute or die $dbh->errstr;
my ($field1, $field2, $field3) = (undef, undef, undef); 
$sth->bind_columns(undef, \($filed1, $field2, field3));
   
while($sth->fetch())
{
    print "$filed1 $field2 $field3\n";
}

Автор: gcc 14.6.2008, 04:57
Цитата(yorm @ 12.6.2008,  16:41)
Подскажите, пожалуйста

я делаю запрос в postgres через DBD

Код

...
$sth = $dbh->execute($blah);
while (my $row = $sth->fetchrow_arrayref()) {
    # some calculations
}


я так понимаю, что возврат уже инкапсулирован в sth?
а можно ли как-то ограничить возврат?

т.е. если возвращается, например 1000 записей, выбрать сначала 100, потом еще и еще (реальная база имеет около десятка миллиардов записей). Чтобы не хранить все в памяти?
или такое невозможно и придется пользовать лимит в запросе?

и можно ли как-то оптимизировать выборку возврата, чтобы работала побыстрее и занимала поменьше памяти? (т.е не через SQL оптимизировать, а именно алгоритм выборки)

Код

limit 


вот пример

Код

$sthh = $dbh->prepare("
        SELECT count(*) FROM com where nam= ?
        ");
$sthh->execute($iddd);
#$sthh->finish();
#$from=1;
($rv)=$sthh->fetchrow_array();
$total_articles_number = $rv;
#$total_articles_number = 79;   #����� ���������� ������
$articles_per_page=10; # ���������� ������ �� ��������
#�������� ���������� �������
#$total_pages = ceil($total_articles_number/$articles_per_page);
$total_pages = floor($total_articles_number/$articles_per_page);
if ($from > $total_pages ) {
$from=$total_pages-1;
}
$jj=0;
#$ii=0;
if ($from eq "") {
$jj=0;
#$ii=0;
#$jj=0;
#$ii=10;
}
else {
$jj=0;
#$ii=0;
$jj=$from*$articles_per_page;
#$ii=($from*$articles_per_page)+10;
}
#print "$jj _ $ii _ $from";
#$sthh->finish();
#$from=1;
$sth = $dbh->prepare("
        select 
id,
nam,
tex,
regr
        from com
        where
        nameid = ?
                LIMIT ?, 10
");
$sth->execute($iddd,$jj);
$dbh->disconnect();
#$sth->finish();
#  $rv = $sth->rows;
#$from=1;
$page_number=-1;
# ��������� ���� - ���������� �������� ����� ���������� �������
print << "[INFO]";
</TABLE>
bla-bla 
<TR>
        <TD background="images/tjpg" WIDTH=263 HEIGHT=100% ALT="" valign="top">
<center>
[INFO]
for ($i=-1; $i<$total_pages; $i++) {
# �������� �������� $from (��� $page_number) ��� ������������� � ������������ ������
#$page_number=$i*$articles_per_page;п╒п╣п╨я│я┌ п║п╬п╬п╠я┴п╣п╫п╦я▐:
# ���� $page_number (���������� ��� �������� ���� �������� �� $from �������) �� ������������� ������� ��������,
# ������� ������ �� �������� �� ��������� $from ������ $page_number
$page_number++;
last if ($total_pages < 1);
next if ($page_number > $from+3);
next if ($page_number < $from-3);
if ($page_number!=$from) {
#$page_number++;
print << "[INFO3]";
 <a href="http://.org/sites/index2.pl?idd=$iddd&from=$page_number"> | $page_number |</a> 
[INFO3]
}
# ����� ������ ������� ����� �������� - ������ ������ �������������,
# ��������� �� �� ������ �������� ���� �� ������� ��������
else {print $i+1;} # ���� page_number - ������� �������� - ������ �� ������� (������ �� ������)
}

Автор: ginnie 16.6.2008, 11:55
Уважаемый gcc, вариант с LIMIT будет тормозить при больших значениях смещения. Лучше использовать конкретные значения id (проиндексированное уникальное возрастающее числовое значение), если такое поле есть в таблице (SELECT ... WHERE id > NNNN LIMIT 10).

Автор: sir_nuf_nuf 18.6.2008, 10:37
А они и не будут хранится все в памяти.
Данные не должны извлекаться из базы в момент $dbh->execute($blah).
СУБД будет выдавать тебе данные по мере необходимости, т.е. 
при каждом вызове $sth->fetchrow_arrayref() ты будешь получать кусочек от результата твоего запроса.

P.S. на самом деле данные передаются не по строке, а большими кусками, но никак не все сразу.

Достаточно открыть какой - нть sql_plus или psql и сделать select * from biiiiig_taaable;
Результат ты получишь быстро, очевидно, что не всю таблицу в память клиентского приложения перекачали.

Автор: gcc 25.4.2009, 18:37
Цитата(ginnie @ 16.6.2008,  11:55)
Уважаемый gcc, вариант с LIMIT будет тормозить при больших значениях смещения. Лучше использовать конкретные значения id (проиндексированное уникальное возрастающее числовое значение), если такое поле есть в таблице (SELECT ... WHERE id > NNNN LIMIT 10).

есть модуль http://kobesearch.cpan.org/htdocs/DBIx-Abstract/DBIx/Abstract.pm.html#clone-

а как написать запрос без LIMIT, как с эмулировать его?

что такое "уникальное возрастающее числовое значение"? если id, но если какая-го данная строка в диапазоне лимита будет удалена как тогда лимит сделать?


Автор: ginnie 27.4.2009, 12:38
Цитата(gcc @  25.4.2009,  18:37 Найти цитируемый пост)
а как написать запрос без LIMIT, как с эмулировать его?


Почему возникла необходимость писать запрос без LIMIT? Я не говорил, что его нужно избегать, я лишь написал, что следует избегать использования больших смещений в LIMIT, заменяя их (по возможности) на использование условий с id. Например, запрос 

Код

SELECT url FROM links ORDER BY id LIMIT 100000, 20


лучше заменить на 

Код

SELECT url FROM links WHERE id > 100000 ORDER BY id LIMIT 20


Автор: gcc 27.4.2009, 12:42
тогда я не так понял.....

вот в этом модуле нету LIMIT http://kobesearch.cpan.org/htdocs/DBIx-Abstract/DBIx/Abstract.pm.html#clone-

как его сделать LIMIT? 

(или там надо переделать модуль сам?)

Автор: ginnie 27.4.2009, 17:32
gcc, к сожалению, никакого опыта работы с этим и подобными ему модулями у меня нет, поэтому ничего конкретного посоветовать не могу. Посмотри, http://wiki.class-dbi.com/wiki/Cdbi_pagers тоже описывается проблема с LIMIT в подобных модулях.

Автор: sir_nuf_nuf 27.4.2009, 18:13
gcc, пожалуй что надо.
Фишка в чем - с точки зрения ORM - выборка - это множество объектов
Из принципов СУБД - выборка неупорядочена (если нет явного указания) и в принципе порядок объектов может
отличаться при повторных запросах.

Тогда с какого бока ORM должна сама ограничивать множество выбираемых объектов. Это не ее дело.

Вставляйте SQL код 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)