Полагаю, под «масштабированием» вы подразумеваете не просто производительность, а техническое обслуживание.
Ключевым изменением вашего кода является передача аргументов в виде пар столбец / значение, а не списка значений с предполагаемым набором столбцов. Это позволит вашему коду обрабатывать любые новые столбцы, которые вы можете добавить.
DBI->selectcol_arrayref
удобен и немного быстрее, будучи написанным на C.
Если вы включите RaiseError
в своем вызове connect
, DBI сгенерирует исключение из-за ошибок, вместо того, чтобы постоянно писать or die ...
. Ты должен это сделать.
Наконец, так как мы пишем SQL из, возможно, ненадежного пользовательского ввода, я позаботился о том, чтобы избежать имени столбца.
Остальное объясняется в на этом Etherpad , вы можете наблюдать, как ваш код будет постепенно преобразовываться.
sub get_ids {
my %search = @_;
my $sql = 'SELECT id FROM files';
if( keys %search ) {
$sql .= " WHERE ";
$sql .= join " AND ", map { "$_ = ?" }
map { $dbh->quote_identifier($_) }
keys %search;
}
return $dbh->selectcol_arrayref($sql, undef, values %search);
}
my $ids = get_ids( foo => 42, bar => 23 );
Если вы ожидаете, что get_ids
вернет огромный список, слишком большой для хранения в памяти, тогда вместо извлечения всего массива и сохранения его в памяти вы можете вернуть дескриптор оператора и повторить с ним.
sub get_ids {
my %search = @_;
my $sql = 'SELECT id FROM files';
if( keys %search ) {
$sql .= " WHERE ";
$sql .= join " AND ", map { "$_ = ?" }
map { $dbh->quote_identifier($_) }
keys %search;
}
my $sth = $dbh->prepare($sql);
$sth->execute(values %search);
return $sth;
}
my $sth = get_ids( foo => 42, bar => 23 );
while( my $id = $sth->fetch ) {
...
}
Вы можете комбинировать оба подхода, возвращая список идентификаторов в контексте массива или дескриптор оператора в скаляре.
sub get_ids {
my %search = @_;
my $sql = 'SELECT id FROM files';
if( keys %search ) {
$sql .= " WHERE ";
$sql .= join " AND ", map { "$_ = ?" }
map { $dbh->quote_identifier($_) }
keys %search;
}
# Convenient for small lists.
if( wantarray ) {
my $ids = $dbh->selectcol_arrayref($sql, undef, values %search);
return @$ids;
}
# Efficient for large ones.
else {
my $sth = $dbh->prepare($sql);
$sth->execute(values %search);
return $sth;
}
}
my $sth = get_ids( foo => 42, bar => 23 );
while( my $id = $sth->fetch ) {
...
}
my @ids = get_ids( baz => 99 );
В конечном итоге вы захотите прекратить ручное кодирование SQL и использовать сопоставитель объектных отношений (ORM), например DBIx :: Class . Одним из основных преимуществ ORM является то, что он очень гибкий и может сделать все для вас. DBIx :: Class может возвращать простой список результатов или очень мощный итератор. Итератор ленив, он не будет выполнять запрос, пока вы не начнете извлекать строки, что позволит вам изменять запрос по мере необходимости, не усложняя процедуру извлечения.
my $ids = get_ids( foo => 23, bar => 42 );
$ids->rows(20)->all; # equivalent to adding LIMIT 20