<!doctype html public "-//W3C//DTD W3 HTML//EN">
<html><head><style type="text/css"><!--
blockquote, dl, ul, ol, li { padding-top: 0 ; padding-bottom: 0 }
 --></style><title>yapop</title></head><body>
<div>Yet Another Perl Optimization Puzzle.</div>
<div><br></div>
<div>Okay, I admit it - I'm weird.  I wrote a program called
sqlpj[1] that uses Tim Bunce's JDBC module, which is his experimental
wrapper to expose java.sql classes via Inline::Java.</div>
<div><br></div>
<div>I like JDBC because it is easy and it is ubiquitous. 
Everything is in one jar for each database.  Every vendor has
one.</div>
<div><br></div>
<div>I don't like DBI:: as much, because it means a couple days stuck
in the CPAN mud to get it installed for various databases. 
Frankly, that has always been a barrier to me, so I never bothered to
spend much serious time with it.</div>
<div><br></div>
<div>(JDBC.pm has similar (cpan) problems because there is an
impedance mismatch somewhere which prevents it from installing
cleanly.  Long story short: work-around is to use perl 5.8.9 or
lower.  However, you only have to install it once, for all
databases.)</div>
<div><br></div>
<div>Writing a front-end to SQL in perl is a joy compared to writing
it in java.  As I derived the perl program from an earlier java
program, I have some knowledge on the issue.  For example, you
can treat JDBC meta calls as data, and voila, you have a full jdbc
meta-data explorer for the price of a cut-and-paste from the
javadocs.</div>
<div><br></div>
<div>All was well until I did a query that returned a million rows. 
Then things got dull, as I waited for the cursor to return.</div>
<div><br></div>
<div>As usual, my initial idea about what was wrong was, well wrong. 
What's the saying?  <a
href="http://c2.com/cgi/wiki?ProfileBeforeOptimizing">Measure twice,
optimize once</a>?</div>
<div><br></div>
<div>So I did, and not surprisingly[2], all my time was getting spent
in the loop that fetched from the JDBC Result set (<a
href=
"http://docs.oracle.com/javase/1.5.0/docs/api/java/sql/ResultSet.html"
>java.sql.ResultSet</a>):</div>
<div><br></div>
<div>    while ($rset->next()) {<br>
        push @allrows,
[&getRow($rset, $self->getXmlDisplay(), @colmap)];</div>
<div>    }</div>
<div><br></div>
<div>Here "rset" is a reference to an instance of
java.sql.ResultSet.  As you can see, all the work is done in
getRow.  Here is the relevant loop there:</div>
<div><br></div>
<div>sub getRow</div>
<div>{</div>
<div>...</div>
<div>    my $m       
= $rset->getMetaData();<br>
    my $colcnt   =
$m->getColumnCount();<br>
    for (my $ii = 1; $ii <= $colcnt; $ii++) {<br>
        next unless
($colmap[$ii-1]);   #skip if column is not selected<br>
<br>
        #note - you have to do the
fetch first,<br>
        #which sets wasNull() for
the current column.<br>
        my $str =
$rset->getString($ii);<br>
<br>
        #if we are displaying xml
rowsets...<br>
        if ($xmldisplay) {<br>
           
#...then set SQL NULL elements to undef:<br>
           
push @data, ($rset->wasNull() ? undef : $str);<br>
        } else {<br>
           
#otherwise, we will display the string "(NULL)":<br>
           
push @data, ($rset->wasNull() ? "(NULL)" : $str);<br>
        } </div>
<div>...</div>
<div>}</div>
<div><br></div>
<div>Geez, lots of opportunities for optimization here, where should I
start?</div>
<div><br></div>
<div>What would you do to improve the performance here?</div>
<div><br></div>
<div>I will post what I actually did in a couple of days to give you a
chance to think about it.</div>
<div><br></div>
<div>Hint: anything derived from $rset is handled by Inline::Java,
which means at least one write/read cycle to a socket connected java
VM.</div>
<div><br></div>
<div>cheers,</div>
<div>-Russ</div>
<div><br></div>
<div><br></div>
<div>[1] I will be posting the source for sqlpj soon, but email me if
you are interested.</div>
<div>[2] After the fact, it was not surprising, as little is.</div>
<div><br></div>
</body>
</html>