I assume that you โzoom inโ you mean in terms of service, not performance.
The key change to your code is to pass your arguments as column / value pairs, not a list of values โโwith an intended set of columns. This will allow your code to handle any new columns that you might add.
DBI->selectcol_arrayref is convenient and slightly faster, written to C.
If you enable RaiseError in your connect call, the DBI will throw an error exception and not write or die ... all the time. You have to do it.
Finally, since we are writing SQL from possibly unreliable user input, I took care to avoid the column name.
The rest is explained in this Etherpad , you can watch how your code will be converted step by step.
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 );
If you expect get_ids return a huge list, too much to store in memory, instead of pulling out the entire array and storing it in memory, you can return the instruction handle and repeat it.
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 ) { ... }
You can combine both approaches by returning a list of identifiers in the context of an array or an instruction handle in scalar format.
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; }
In the end, you need to stop manual SQL coding and use Map Relation Mapper (ORM) like DBIx :: Class . One of the main advantages of ORM is its very flexible approach and can do the above for you. DBIx :: Class can return a simple list of results or a very powerful iterator. The iterator is lazy, it will not execute the request until you start receiving rows, which will allow you to modify the query as necessary without having to complicate your fetch procedure.
my $ids = get_ids( foo => 23, bar => 42 ); $ids->rows(20)->all;