in reply to Re: Re: prepare_cached for DBI::Oracle
in thread prepare_cached for DBI::Oracle

Just forget the above code, it is rather useless
My head is certainly not working well today (o:

Ok, to be simplier. I just put the relevant info here. Both SQL statement are prepared_cached, but only the second one is working...
I also tried to add code to track down error message, but nothing is returned )o;
I bet the solution is silly as hell, but I can't find it... maybe need some rest (o;{{
$sth_imei = $dbh->prepare_cached(<<__EOSQL__); SELECT imei FROM imei_period WHERE (mobile_number = ?) AND (account_no = ?) __EOSQL__ $sth_acc = $dbh->prepare_cached(<<__EOSQL__); SELECT customer.password, to_char(max(ar_open.bill_date),'DD.MM.YYYY') FROM customer, ar_open WHERE (customer.account_no = ar_open.account_no) AND (customer.account_no = ?) GROUP BY customer.password, to_char(sysdate,'DD.MM.YYYY'), to_char(sysdate,'HH24:MI:SS') __EOSQL__ # [..] $sth_imei->execute($rec[1],$rec[0]); @imei = $sth_imei->fetchrow_array; print "IMEI : @imei\n"; # This does not return anything )o; $sth_acc->execute($rec[0]); @acc = $sth_acc->fetchrow_array; print "ACC : @acc\n"; # This one works fine

Replies are listed 'Best First'.
DBI-trace()
by Arguile (Hermit) on Jun 22, 2001 at 16:36 UTC

    DBI->trace() is your friend and so is $sth->errstr.

    First up is $sth->errstr who you really should be using after all your prepare and execute statements like this:

    $sth->execute($foo,$bar) or die "Couldn't execute query:" . $sth->errstr;

    DBI->trace() is more a development tool, it has multiple levels of tracing for very effecient debugging.

    LEVEL | EFFECT -------------------------------------------- 0 Disable trace 1 Execution trace (values and errors) 2 L1 + method and params 3 L2 + driver level (very detailed) 4 An insane amount of information

    The DBI->trace(2, 'tracefile') takes one or two parameters, the first is the trace level as illustrated above, the second is an optional file to dump the debugging log into.

    I'm recalling this out of Programming the Perl DBI which is an excellent book, but it's on loan to a friend so I hope the table's correct. I was/am preparing a more detailed post given some of your other code (Oracle DBA here, so this stuff is fun for me) but I'm pretty busy so I thought I'd just share this until I get a few moments

    Update: Added the $sth->errstr() stuff then noticed it had already been mentioned by andye

    Update 2: Have a few more moments, I'd really like to go over your general query structure but that would take more time than I currently have so let's stick to some little things (BTW brovnick covered a really good point, personally I see $count as very perplexing given you can just iterate over the cursor):

    # The main Select $sth_main = $dbh->prepare(<<'__EOSQL__'); SELECT DISTINCT t.account_no, t.telephony_id, n.sim, n.mobile_number, s.user_name, s.contract_status, s.dealer, to_char(t.eff_start_date,'DD.MM.YYYY'), to_char(s.signed_date,'DD.MM.YYYY'), to_char(s.subscr_change_upd,'DD.MM.YYYY'), lpad(s.s_id,7,'0'), to_char(t.eff_start_date,'HH24:MI:SS') FROM new_sim n, subscription s, tele_period t WHERE (t.account_no = n.account_no) AND (t.telephony_id = n.mobile_number) AND (t.account_no = s.account_no) AND (t.telephony_id = s.mobile_number) ORDER BY t.account_no, t.telephony_id __EOSQL__

    Notice the single quotes around __EOSQL__? By default here docs are interpolated, you don't want perl to spend the time checking and you certainly don't want it interpolating in this case. So explicitly state it as shown. Also, if you want, you can use table aliases. I handle a lot of queries a day and it's so much faster to type and easier to read when they're used (check the FROM clause to see how it's done).

    # using an array ref instead $rec = $sth_main->fetchrow_arrayref('NAME_lc') $sth_imei->execute( $rec->[1], $rec->[0] ) or die $sth_imei->errstr; # using a hash ref $rec = $sth_main->fetchrow_hashref('NAME_lc'); $sth_imei->execute( $rec->{telephony_id}, $rec->{account_no}) or die $sth_imei->errstr;

    Using a fetched reference instead of an array is much faster and uses less memory, b/c each time your cursor moves (ie. iterate to the next record) DBI uses the same memory space instead of creating a new array. This would necesitate some major changes to your structure, but if you want more speed you'll probably be doing them anyways.

    The hash reference is a bit slower on lookup simply b/c it is a hash, however, the benefits of it should be obvious. Now $rec actually means something instead of being just a number.

    P.S. Consider joining, it's painless: It's also much nicer talking to a name than Anonymous Monk
      Ok, I made a new friend (o:
      put the DBI->trace() and Damn, this is usefull (o;

      Strange, the $sth_imei execute successfully, but now rows are returned )o:
      If tried directly in SQLPlus with the values which are binded, it works and returns the value I seek...

      I also try to use this (__EOSQL__) and all to clean up my code as it is crap (o:{{

      I am going to look into the hash reference...
Re: Code useless, forget it... this is more usefull (o;
by andye (Curate) on Jun 22, 2001 at 16:57 UTC
    • I suggest you put in error conditions in case the prepare_cached or the execute fails. You can get the database error message using  $dbh->errstr - it's often very helpful.
    • Are you sure that you're finishing both of the statement handles? In the larger chunk of code above, there's only one finish.
    • You could try doing bind_param separately from execute, in case the problem's there
    • In answer to someone's question below, 'clockwork'. ;)
    Hope that's even a bit helpful,

    andy.

Re: Code useless, forget it... this is more usefull (o;
by Brovnik (Hermit) on Jun 22, 2001 at 17:11 UTC
    OK, I see nothing obviously wrong in this snippet, but...
    (Apologies if this is teaching you to suck eggs)

    1. If your main concern is overall speed, I suggest some detailed profiling. Find where the code is spending most of its time. See Benchmark. Use the Benchmark->new and timediff() methods to look at checkpoints. Since you are doing lots of logging anyway, have your loggit() call put a timestamp in the LOG.

    • Prepare_cached is only going to save you time if it takes a long time to do the actual prepare and you call it lots of times. It could be that if the datasets are large the time is taken in the execute(), and not the prepare().
    • Depending on your DB config, load on the server, and systems could be a factor.
    • You seem to be collecting all the values and then only using the first 15 or 10 lines. How about using a LIMIT command to reduce the lines computed/returned by the SQL.
    • There may be other SQL/DB efficiency ideas, but I am not the person to ask about that. I expect that a good time profile will help you narrow down the issues better.

    2. Have you turned on the error checking in the DB ?

    {RaiseError=>1}
    in the connect(). It could be that there is a problem in the prepare() line.

    3. Is it only failing if you use prepare_cached ? I.E. does it work without the _cached ?

    4. Are you using the $sth->finish() when no longer needed ? This can generate errors if there is an open execute and _cached is called again.

    That's all I can think of right now, good luck.
    --
    Brovnik

    • How about using a LIMIT command ...
      unfortunately, LIMIT is not valid in ORACLE )o; and I call both of the one I detail about 80 000 times...
    • I tried to bind the values.. same problem...
      $sth_imei = $dbh->prepare_cached(<<__EOSQL__) or die "Couldn't parse q +uery:".$sth_imei->errstr; SELECT imei FROM imei_period WHERE (mobile_number = :mob) AND (account_no = :acc) __EOSQL__ $sth_imei->bind_param( ':mob', $rec[1] ); $sth_imei->bind_param( ':acc', $rec[0] ); $sth_imei->execute() or die "Couldn't execute query:" . $sth_imei- +>errstr; @imei = $sth_imei->fetchrow_array; print "IMEI : @imei\n";
      When executed, the $sth_imei->errstr does not return anything...
      I check, the SQL works and return the requested infor if executed in SQLPlus...

      This is very frustrating, especially since the $sth_acc one is working fine...
    • for $sth->finish() I thought I should not use it as it was cached ??
      But yes, I do not use it much...
    • Ihad the PrintError => 1, set, but not the RaiseError one.
      If I use RaiseError => 1 it doesnot change a thing )o; still no error reported...

      I will go for a perl -w I think... (o;
        A couple more ideas (sparked by the 80,000) :
        1. Try binding the return values. e.g.
          my $imei; $rc = $sth_imei->bind_col(0,\$imei); $sth_imei->execute(); $sth_imei->fetch(); print "IMEI : $imei\n";
        2. If you don't want to do that, at least use ->fetchrow_arrayref(). Otherwise, each execute call has to create a new list for you. The _arrayref gives you a ref. to a static array, so less copying.
        3. bind_param should take a colum number shouldn't it, not a name, e.g. $sth_imei->bind_param(0,$rec[1])
        Either of the first 2 should save time, given 80,000 iterations.
        Finally, note that execute() can return '0E0' meaning 0 but true, meaning no rows (and different to undef for errors). May be worth checking for that explicitly.
        I think I'm out of ideas now...
        --
        Brovnik
      3. Without the "_cached", it does not seems to change anything.....

      I used DBI->trace as Arguile wisely suggested, and it looks like all is fine... strange...
      The Statement is prepared, the parameter binded, and the all thing is executed successfully.
      BUT it returns nothing ([0] items).

      if I cut and paste the SQL from the Perl, and replace the :mob and :acc by the binded values in the log file, it returns the value fine (the entrie does exist in the table...).

      Maybe I look for an error in the Perl when I should go and seek the wisdom of the DBA Administrator as he might have error log of my activities....