[Rt-devel] Postgres performance issues and some "odd" ways to get IDs...

Joby Walker joby at u.washington.edu
Mon Aug 14 13:03:36 EDT 2006


Jesse,

The new behavior seems very broken:

1) Insert row (sequence nextval returns x)
2) get current value of sequence (returns x)

As far as I can see SearchBuilder doesn't wrap a transaction around the 
Insert sub so you could end up with unpredictable results:

1) Process 1: Insert row (sequence nextval returns x)
2) Process 2: Insert row (sequence nextval returns x+1)
3) Process 1: get current value of sequence (x+1)
4) Process 2: get current value of sequence (x+1)

Wrapping a transaction around it should solve the problem, but you would 
be adding transaction overhead for no gain.  What Matt wrote is the best 
behavior (it is also what other DB object models use such as PHP's Propel):

1) get nextval of sequence (x)
2) insert row with id of x.

This cannot be munged by multiple processes:

1) Process 1: get nextval of sequence (x)
2) Process 2: get nextval of sequence (x+1)
3) Process 1: insert row (id = x)
4) Process 2: insert row (id = x+1)

While it is unlikely that the SearchBuilder behavior would actually end 
up with a wrong result, the probability is non-zero.  Very little code 
change would be necessary (see attached -- and I haven't tested 
this...).  The only downside would be a gap in the sequence when the 
insert failed.

Joby Walker
C&C SSG, University of Washington


Jesse Vincent wrote:
> 
> 
> On Tue, Aug 15, 2006 at 01:24:30AM +1000, Matthew Sullivan wrote:
>> Hey All,
>>
>> the only slow queries... needless to say I was surprised when I saw what 
>> it was doing (eg: SELECT id from Transactions where oid = <blah>;) ... 
>> further inspection lead me to DBIx::SearchBuilder::Handle::Pg::Insert() 
>> ... and the following:
> 
> Why don't you try upgrading DBIx::SearchBuilder:
> 
> http://search.cpan.org/src/JESSE/DBIx-SearchBuilder-1.43/SearchBuilder/Handle/Pg.pm
>> sub Insert {
> ...
>>    my $sql = "SELECT id FROM $table WHERE oid = ?";
>>    my @row = $self->FetchResult($sql, $oid);
>>    # TODO: Propagate Class::ReturnValue up here.
>>
>> Comments/flames welcome...
>>
>> Regards,
>>
>> Mat
>>
>> PS: It's 1:15am here after 6 hours of database performance debugging, 
>> apologies if the above offends, it is not meant to.
>>
> 
> But maybe only after you get a bit of rest. Best luck. Please tell us if
> this helps.
> 
> Jesse
> _______________________________________________
> List info: http://lists.bestpractical.com/cgi-bin/mailman/listinfo/rt-devel
-------------- next part --------------
--- Pg.pm	2006-08-14 10:00:28.255968250 -0700
+++ Pg.pm.new	2006-08-14 10:01:07.138398250 -0700
@@ -61,24 +61,23 @@
     my $self  = shift;
     my $table = shift;
     my %args  = (@_);
+
+    unless($args{'id} || $args{'Id'}) {
+        my $sequence_name = $self->IdSequenceName($table);
+        unless ($sequence_name) { return ($sequence_name) }   
+        my $seqsth = $self->dbh->prepare(
+            qq{SELECT NEXTVAL('} . $sequence_name . qq{')} );
+        $seqsth->execute;
+        $args->{'id'} = $seqsth->fetchrow_array();
+    }
+
     my $sth   = $self->SUPER::Insert( $table, %args );
 
     unless ($sth) {
         return ($sth);
     }
 
-    if ( $args{'id'} || $args{'Id'} ) {
-        $self->{'id'} = $args{'id'} || $args{'Id'};
-        return ( $self->{'id'} );
-    }
-
-    my $sequence_name = $self->IdSequenceName($table);
-    unless ($sequence_name) { return ($sequence_name) }   # Class::ReturnValue
-    my $seqsth = $self->dbh->prepare(
-        qq{SELECT CURRVAL('} . $sequence_name . qq{')} );
-    $seqsth->execute;
-    $self->{'id'} = $seqsth->fetchrow_array();
-
+    $self->{'id'} = $args{'id'} || $args{'Id'};
     return ( $self->{'id'} );
 }
 


More information about the Rt-devel mailing list