Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 633557
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 13, 20262026-05-13T20:11:58+00:00 2026-05-13T20:11:58+00:00

Disclaimer: first time I’ve used DBI. I have a MySQL table with a lot

  • 0

Disclaimer: first time I’ve used DBI.

I have a MySQL table with a lot of indexed fields (f1, f2, f3, etc) that are used to generate WHERE clauses by long-running processes that iterate over chunks of the database performing various cleaning and testing operations.

The current version of this code works something like this:

sub get_list_of_ids() {
    my ($value1, $value2, $value3...) = @_;

    my $stmt = 'SELECT * FROM files WHERE 1';
    my @args;

    if (defined($value1)) {
        $stmt .= ' AND f1 = ?';
        push(@args, $value1);
    }
    # Repeat for all the different fields and values

    my $select_sth = $dbh->prepare($stmt) or die $dbh->errstr;
    $select_sth->execute(@args) or die $select_sth->errstr;

    my @result;
    while (my $array = $select_sth->fetch) {
        push(@result, $$array[0]);
    }
    return \@result;
}

sub function_A() {
    my ($value1, $value2, $value3...) = @_;

    my $id_aref = get_list_of_ids($value1, $value2, $value3...);
    foreach my $id (@$id_aref) {
        # Do something with $id
        # And something else with $id
    }
}

sub function_B() {
    my ($value1, $value2, $value3...) = @_;

    my $id_aref = get_list_of_ids($value1, $value2, $value3...);
    foreach my $id (@$id_aref) {
        # Do something different with $id
        # Maybe even delete the row
    }
}

Anyway, I’m about to dump an awful lot more rows in the database, and am well aware that the code above wont scale up. I can think of several ways to fix it based on other languages. What is the best way to handle it in Perl?

Key points to note are that the logic in get_list_of_ids() is too long to replicate in each function; and that the operations on the selected rows are very varied.

Thanks in advance.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-13T20:11:59+00:00Added an answer on May 13, 2026 at 8:11 pm

    I presume by “scale up” you mean in maintenance terms rather than performance.

    The key change to your code is to pass in your arguments as column/value pairs rather than a list of values with an assumed set of columns. This will allow your code to handle any new columns you might add.

    DBI->selectcol_arrayref is both convenient and a bit faster, being written in C.

    If you turn on RaiseError in your connect call, DBI will throw an exception on errors rather than having to write or die ... all the time. You should do that.

    Finally, since we’re writing SQL from possibly untrusted user input, I’ve taken care to escape the column name.

    The rest is explained in this Etherpad, you can watch your code be transformed 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 to return a huge list, too much to keep in memory, then instead of pulling out the whole array and storing it in memory you can return the statement handle and iterate with that.

    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 IDs in array context, or a statement handle in scalar.

    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 );
    

    Eventually you will want to stop hand coding SQL and use an Object Relation Mapper (ORM) such as DBIx::Class. One of the major advantages of an ORM is it is very flexible and can do the above for you. DBIx::Class can return a simple list of results, or very powerful iterator. The iterator is lazy, it will not perform the query until you start fetching rows, allowing you to change the query as needed without having to complicate your fetch routine.

    my $ids = get_ids( foo => 23, bar => 42 );
    $ids->rows(20)->all;  # equivalent to adding LIMIT 20
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Disclaimer:It's my first time developing an app that will be on a tablet style
Disclaimer: This is my first time writing unit tests...be gentle! :) I am trying
Disclaimer: the following is a sin against XML. That's why I'm trying to change
Disclaimer Yes, I am fully aware that what I am asking about is totally
Been a while since I've dealt with ASP.NET and this is the first time
I'm a long-time C++ programmer developing on Windows, and have been using Visual Studio
first is the disclaimer, I did not design the database I am now supporting
Background / Disclaimer First of all, please feel free to skip this entirely if
[Disclaimer] I am very new to Haskell (and any FPL for that matter), just
(Disclaimer: I have removed the Qt tag in case the problem is in my

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.