On 19-11-2011 13:28, Reinier Olislagers wrote:
> Hi list,
> 
> The Firebird/Interbase ibconnection.pp code has this code in its
> SetParameters procedure to upload blobs in segments (BlobSegmentSize
> property is set to 80 on object creation):
>       while BlobBytesWritten < (BlobSize-BlobSegmentSize) do
>         begin
>         isc_put_segment(@FStatus[0], @blobHandle, BlobSegmentSize,
> @s[(i*BlobSegmentSize)+1]);
>         inc(BlobBytesWritten,BlobSegmentSize);
>         inc(i);
>         end;
>       if BlobBytesWritten <> BlobSize then
>         isc_put_segment(@FStatus[0], @blobHandle,
> BlobSize-BlobBytesWritten, @s[(i*BlobSegmentSize)+1]);
> 
> I've asked the Firebird list whether we need to upload in segments and
> the answer is no, you can upload in chunks of up to 65535 bytes (see below).
> 
> Would getting rid of the BlobSegmentSize property and replacing it by a
> BlobSegmentSize const set at 65535 make sense (e.g. for performance)?

Did a small performance test:
- once with 80, once with 65535
- 10MB blobs
- Firebird 2.5 server
- on a virtual machine (just restored from snapshot before each run)
The difference seems fairly big: 395 seconds versus 260 seconds

Hope I'm testing correctly.

Test code is attached; I'd appreciate confirmation.

Also attached is a patch for ibconnection.pp against FPC fixes_2_6.
I set the BlobSegmentSize property to deprecated and basically ignored
the underlying variable when writing blobs.

I wonder whether/what changes are required for reading blobs...

Thanks,
Reinier


program firebirdsegment;
{ Tests blob writing performance on Firebird/Interbase databases;
try varying the BlobSegmentSize below }
{
CREATE TABLE TESTTABLE
(
  BLOBCOL BLOB SUB_TYPE 1,
  ID INTEGER NOT NULL,
  CONSTRAINT PK_TESTTABLE_0 PRIMARY KEY (ID)
);
}
{$mode objfpc}{$H+}
{$APPTYPE CONSOLE}
uses {$IFDEF UNIX} {$IFDEF UseCThreads}
  cthreads, {$ENDIF} {$ENDIF}
  Classes,
  SysUtils,
  sqldb,
  ibconnection {Firebird access},
  dateutils; 

var
  FConnection: TIBConnection;
  FQuery: TSQLQuery;
  FTransaction: TSQLTransaction;
  RecordCounter: integer;
  TextCounter: integer;
  Recordtext: string='';
  Currenttime: Tdatetime;
  Endtime: Tdatetime;    
begin
  FConnection:=TIBConnection.Create(nil);
  FConnection.CharSet := 'UTF-8';
  FConnection.DatabaseName := 'test.fdb';
  FConnection.HostName := paramstr(1); //first command line argument
  FConnection.UserName := 'SYSDBA';
  FConnection.Password := 'masterkey';   
  FConnection.Dialect := 3;
  //FConnection.BlobSegmentSize:=80;
  FConnection.BlobSegmentSize:=65535;
  FConnection.Connected:=true;
  FTransaction := TSQLTransaction.Create(nil);
  FConnection.Transaction := FTransaction;
  FQuery := TSQLQuery.Create(nil);
  FQuery.Database := FConnection;  
  FQuery.Close;
  FQuery.SQL.Text := 'SELECT ID, BLOBCOL FROM TESTTABLE;';
  
  //10 meg
  for TextCounter := 1 to 10485760 do
  begin
    RecordText := RecordText + '1';
  end;
  
  writeln('BlobSegmentSize = ' + IntToStr(FConnection.BlobSegmentSize));
  CurrentTime:=now(); 
  for RecordCounter := 0 to 500 do
  begin
    if (RecordCounter mod 10)=0 then
    begin
      // Free up space
      writeln('Cleanup at record ' + inttostr(recordcounter));
      FTransaction.Active:=True;
      FConnection.ExecuteDirect('DELETE FROM TESTTABLE');
      FTransaction.Commit;
      FTransaction.Active := True;
    end;
    Ftransaction.Active:=true;
    FQuery.Open;
    FQuery.Insert;
    FQuery.FieldByName('ID').AsInteger:=RecordCounter;
    FQuery.FieldByName('BLOBCOL').Clear;
    FQuery.FieldByName('BLOBCOL').AsString := RecordText;
    FQuery.Post;
    FQuery.ApplyUpdates;
    FTransaction.Commit;
  end;
  EndTime:=now();
  writeln('Time spent: '+ IntToStr(SecondsBetween(CurrentTime, EndTime)) + ' 
seconds.'); 
  FQuery.Close;
  FTransaction.Active:=false;
  FConnection.Close;
  FQuery.Free;  
  FTransaction.Free;  
  FConnection.Free;
end.
Index: packages/fcl-db/src/sqldb/interbase/ibconnection.pp
===================================================================
--- packages/fcl-db/src/sqldb/interbase/ibconnection.pp (revision 19658)
+++ packages/fcl-db/src/sqldb/interbase/ibconnection.pp (working copy)
@@ -16,6 +16,7 @@
 
 const
   DEFDIALECT = 3;
+  MAXBLOBSEGMENTSIZE = 65535; //Maximum number of bytes that fit in a blob 
segment.
 
 type
 
@@ -51,7 +52,7 @@
     FStatus              : array [0..19] of ISC_STATUS;
     FDialect             : integer;
     FDBDialect           : integer;
-    FBLobSegmentSize     : word;
+    FBLobSegmentSize     : word; //required for backward compatibilty; not used
 
     procedure ConnectFB;
     function GetDialect: integer;
@@ -99,7 +100,8 @@
     constructor Create(AOwner : TComponent); override;
     procedure CreateDB; override;
     procedure DropDB; override;
-    property BlobSegmentSize : word read FBlobSegmentSize write 
FBlobSegmentSize;
+    //Segment size is not used in the code; property kept for backward 
compatibility
+    property BlobSegmentSize : word read FBlobSegmentSize write 
FBlobSegmentSize; deprecated;
     function GetDBDialect: integer;
   published
     property DatabaseName;
@@ -165,7 +167,7 @@
   inherited;
   FConnOptions := FConnOptions + [sqSupportParams] + [sqEscapeRepeat];
   FieldNameQuoteChars:=DoubleQuotes;
-  FBLobSegmentSize := 80;
+  FBLobSegmentSize := 65535; //Shows we're using the maximum segment size
   FDialect := -1;
   FDBDialect := -1;
 end;
@@ -743,7 +745,7 @@
     BlobBytesWritten  : longint;
     
   procedure SetBlobParam;
-  
+
   begin
 {$R-}
     with cursor as TIBCursor do
@@ -759,14 +761,16 @@
       BlobBytesWritten := 0;
       i := 0;
 
-      while BlobBytesWritten < (BlobSize-BlobSegmentSize) do
+      // Write in segments of MAXBLOBSEGMENTSIZE, as that is the fastest.
+      // We ignore BlobSegmentSize property.
+      while BlobBytesWritten < (BlobSize-MAXBLOBSEGMENTSIZE) do
         begin
-        isc_put_segment(@FStatus[0], @blobHandle, BlobSegmentSize, 
@s[(i*BlobSegmentSize)+1]);
-        inc(BlobBytesWritten,BlobSegmentSize);
+        isc_put_segment(@FStatus[0], @blobHandle, MAXBLOBSEGMENTSIZE, 
@s[(i*MAXBLOBSEGMENTSIZE)+1]);
+        inc(BlobBytesWritten,MAXBLOBSEGMENTSIZE);
         inc(i);
         end;
       if BlobBytesWritten <> BlobSize then
-        isc_put_segment(@FStatus[0], @blobHandle, BlobSize-BlobBytesWritten, 
@s[(i*BlobSegmentSize)+1]);
+        isc_put_segment(@FStatus[0], @blobHandle, BlobSize-BlobBytesWritten, 
@s[(i*MAXBLOBSEGMENTSIZE)+1]);
 
       if isc_close_blob(@FStatus[0], @blobHandle) <> 0 then
         CheckError('TIBConnection.CreateBlobStream isc_close_blob', FStatus);
_______________________________________________
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply via email to