Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello Wise Ones-

I'm in the process of refactoring my code, and I have found a number of mistakes that we had previously made using DBI. While we are now properly using prepared statements with placeholders, in referencing the following (old) post: Tricks with DBI, I found myself getting confused on a couple of areas... Here's the general logic of what I have:
# connect parent $dbh->connect(...); #statement 1 $sth=$dbh->prepare($sql); $sth->execute; while(($var)=$sth->fetchrow_array) { # fork $pm->start and next; # connect child $dbh2->connect(...); #statement 2 $sth2->prepare($sql2); $sth2->execute; while(($var2)=$sth2->fetchrow_array) { # condition if($var) { # statement 3 that might not be called $sth3->prepare($sql3); $sth3->execute; while(($var3)=$sth3->fetchrow_array) { ... } $sth3->finish; } else { # statement 4 that might not be called $sth4->prepare($sql4); $sth4->execute; while(($var4)=$sth4->fetchrow_array) { ... } $sth4->finish; } } # finish statement 2 $sth2->finish; # disconnect child $dbh2->disconnect; # end fork $pm->finish; } # finish statement 1 $sth->finish; # disconnect parent $dbh->disconnect;
With that, I have a handful of questions:
  1. I read that I need to start a new $dbh within each child (which I have done above). Is that correct?
  2. $sth and $sth2 don't seem that they need to be in a prepare_cached(), however $sth3 and $sth4 need to be handled better since they are in a while() loop and may get called multiple times. If I use prepare_cached() here, were would I call the finish()? Or should I just use prepare() and move the prepare()/finish() statements outside of the while loop (then I'm preparing the statement even if it never gets used)?
  3. Is using $sth->bind_columns and $sth->fetch faster/more efficient/preferred to using $sth->fetchrow_array?
  4. Is there anything else that I am doing wrong or can do better with my logic above?
Thank you in advance!

Replies are listed 'Best First'.
Re: DBI, prepare_cached, finish, and forks
by runrig (Abbot) on Feb 24, 2006 at 01:22 UTC
    1. That's right. Don't use the same $dbh in more than one process.
    2. If you fetch all rows and don't exit the loop early, there is no need to call finish(). on sth3 and 4, you can either call prepare_cached, or move the prepare to right before the sth2 fetch loop (which would be my preference...even calls to prepare_cached cost something).
    3. It probably won't make a big difference, but bind_columns w/fetch is supposed to be faster.
      Why thank you!

      2. So if I were to call prepare_cached() within the condition (so I'm not preparing the statement if I don't need it, since there are multiple ones), you're saying that I don't need to call finish() on it?

      I seem to remember getting errors if I don't call the finish() on my statements... are you saying that as long as I fetch all the returned rows on either a prepare() or a prepare_cached(), I don't need to use a finish()?

      I'd assume it's still best practice to use a finish()?

        > I'd assume it's still best practice to use a finish()?

        Nope. From the DBI docs:
        "Adding calls to finish after each fetch loop is a common mistake, don't do it, it can mask genuine problems like uncaught fetch errors."