On 18/05/11 13:10, Shree wrote:

I don't think we can help you because we don't know what HandleIds() does. I 
note it may return -1 and causes all of the remaining ids in your batch to be 
skipped. Some further comments below:

use strict;
use warnings;

my $dsn = 'dbi:Oracle:dbname';
my $user = 'xxxxx';
my $pass = 'xxxxxxxxxxx';
my $attr = {
         FetchHashKeyName =>  'NAME_lc',
         RaiseError =>  1,
         PrintError =>  0,
         AutoCommit =>  0,
         ChopBlanks =>  1,
};

my $rowcount = 11;
my $commitLevel = 10;

my $dbh = DBI->connect($dsn, $user, $pass, $attr);

my $queued_recs = $dbh->prepare("SELECT id from (SELECT id FROM queue
WHERE processed=\'F\' ORDER BY id ASC) where ROWNUM<  $rowcount");

You could prepare your update statement here and avoid calling prepare 
repeatedly.
my $going = 1;

     while($going) {

          $queued_recs->execute();

         my @ids2process;
            while ( my @ids = $queued_recs->fetchrow_array ) {
                 push(@ids2process, $ids[0]);
         }

You know you are only going to get a list of ids back here so why bother 
fetchrow_arraying it only to push onto @ids2process. Why not just 
fetchall_arrayref in one go then loop over those.

         if(!scalar(@ids2process)) {
                 sleep(5);
         }

         if(scalar(@ids2process)>  0 ) {
           my $count=0;

          foreach my $ids (@ids2process){
                 $count++;
                                my $ret = HandleIds($id);
                                next if($ret == -1);

We don't know what HandleIds does and it causes all remaining ids to be 
ignored. This is probably where your problem is.


                                my $updated = '';
                        eval{
                                        my $update_ids = $dbh->prepare("UPDATE 
queue set processed = \'T
\' where id = $ids");
                     $updated = $update_ids->execute();
                        };

A good habit to get into is to use placeholders in your SQL - there are a lot 
of good reasons for this documented all over the place:

prepare the update outside the loop with:

my $update_ids = $dbh->prepare(q/update queue set processed = ? where id = ?/);
then
$update_ids->execute('T', $ids);

                        if($@) { $log->error("Unable to update record for - id: 
$id,
updated: $updated");}
                        else { $log->info("Updated record for - id: $id, 
updated:
$updated");}

What if your code is wrong and you pass an id which does not exist in the table 
- you do not know the update changed nothing. Check $updated contains 1.


            if(($count % $commitLevel  == 0) || ($count ==
scalar(@ids2process)))
                  {
                     my $commited = $dbh->commit;
                     $log->info("COMMIT at $count Ids, commited:
$commited");
                  }

          }

There is something wrong with the above logic due to HandleIds() again. If your 
select returns 10 rows but HandleIds returns -1 for the last id, next causes 
the loop to end and your commit did not get called.  Much better to do:

Personally I don't like turning off AutoCommit like this I prefer to do:

$dbh->begin_work;
  do my work;
$dbh->commit;

i.e., put the commit outside the loop then you don't car how many ids were 
processed, you just commit all the updates.

        }else {
                 sleep(5);
         }
     }

Did you intend to sleep for 10s when there are no ids or 5?

Martin
--
Martin J. Evans
Easysoft Limited
http://www.easysoft.com

Reply via email to