ODBC overseas performance problem

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
17 messages Options
Reply | Threaded
Open this post in threaded view
|

ODBC overseas performance problem

Alan Wostenberg-3
I am using Dolphin 4 trial version to do a concept proof before
converting over a production Visual Works Smalltalk and several VB
apps.

I am using Dolphin ODBC classes reading a Microsoft SQL Server
database over an intraanet connection from Denver to Amsterdam. But
ODBC Performance in Dolphin is much slower than other applications. To
iterate through result set of 4000 records takes 860 seconds (about 4
records/second, rows are just ints and a couple ttimestamp).
Non-Dolphin applications, including the visual works using same ODBC
have about 5x better performance.

I read notes of 2001-03-12 and wonder if Dolphin is fetching one row
at a time so I'm taking a serious network latency hit. Is that
possible, if so, how can I set the blocking factor higher?

By the way, none of the sources for the ODBC classes are visible --
I'm assuming because it's the trial version?

-Alan Wostenberg
Baan, Golden Colorado


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Blair McGlashan
Alan

You wrote in message news:[hidden email]...

> I am using Dolphin 4 trial version to do a concept proof before
> converting over a production Visual Works Smalltalk and several VB
> apps.
>
> I am using Dolphin ODBC classes reading a Microsoft SQL Server
> database over an intraanet connection from Denver to Amsterdam. But
> ODBC Performance in Dolphin is much slower than other applications. To
> iterate through result set of 4000 records takes 860 seconds (about 4
> records/second, rows are just ints and a couple ttimestamp).
> Non-Dolphin applications, including the visual works using same ODBC
> have about 5x better performance.
>
> I read notes of 2001-03-12 and wonder if Dolphin is fetching one row
> at a time so I'm taking a serious network latency hit. Is that
> possible, if so, how can I set the blocking factor higher?

Yes that is true. Dolphin's DB connection was not designed with remote
access in mind, and it does request only a single record at a time. If the
underlying driver is not doing its own batching (I'm surprised it doesn't),
then that is likely to result in very poor performance against a remote
database (and personally I would call 4 recs/sec very poor performance). You
could verify that by comparing performance against a local database.

Oddly this has (as far as I recall) only come up that once before (in a
report from Dmitry Zamotkin), and so I while we have an enhancement entry in
our bug-tracking database to add block fetch support, at the moment there is
no set timescale for it to be actioned. The priority of any enhancement is
mainly a commercial decision based on demand, etc, but we are open to
lobbying and/or specific contractual arrangements :-).

> By the way, none of the sources for the ODBC classes are visible --
> I'm assuming because it's the trial version?

That is right. There is full source for absolutely all the Smalltalk code in
purchased versions. Our VM is purely an execution engine, and we keep its
functionality to a bare minimum, we certainly don't put any database access
code in there, so it would be quite possible (though non-trivial) for you to
add block fetch support yourself. Another option you have in Dolphin would
be to use ADO - you can use the Active-X Component Wizard to generate
wrapper classes for the ADODB component and then use them much like you
would use ADO in VB. With a little manual tweaking it is possible to add
some more idiomatic Smalltalk support (e.g. some collection enumerators)
resulting in a more fluid Smalltalk integration. From my experiments using
ADO in this way is slower than Dolphin's ODBC package for local database
access, but it may be better for remote access.

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Bill Schwab
Alan,

> Another option you have in Dolphin would
> be to use ADO - you can use the Active-X Component Wizard to generate
> wrapper classes for the ADODB component and then use them much like you
> would use ADO in VB. With a little manual tweaking it is possible to add
> some more idiomatic Smalltalk support (e.g. some collection enumerators)
> resulting in a more fluid Smalltalk integration. From my experiments using
> ADO in this way is slower than Dolphin's ODBC package for local database
> access, but it may be better for remote access.

To Blair's reply I'll add that if you go the ADO route (you might want to
check Ian's archives to see if somebody else has already done it), be sure
to take the methods you add/modify out of the autogenerated category.  At
least ask for clarification of the issues before you do a lot of work and
then want to regenerate classes.

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Chris Uppal-3
In reply to this post by Blair McGlashan
Blair,

> Yes that is true. Dolphin's DB connection was not designed with remote
> access in mind, and it does request only a single record at a time. If the
> underlying driver is not doing its own batching (I'm surprised it
doesn't),
> then that is likely to result in very poor performance against a remote
> database (and personally I would call 4 recs/sec very poor performance).
You
> could verify that by comparing performance against a local database.
>
> Oddly this has (as far as I recall) only come up that once before (in a
> report from Dmitry Zamotkin), and so I while we have an enhancement entry
in
> our bug-tracking database to add block fetch support, at the moment there
is
> no set timescale for it to be actioned. The priority of any enhancement is
> mainly a commercial decision based on demand, etc, but we are open to
> lobbying and/or specific contractual arrangements :-).

I also reported finding problems with the Database Connection (I mentioned
them in the original thread).

Since then, I've investigated the problem a little more (but not tried to
fix it); here are some numbers.

My set-up was that Dolphin was talking ODBC to a MS SQLServer7 server
running on the same dual CPU box running NT4.

Using Dolphin I tried (names changed to protect the innocent):

    sql := 'SELECT www, xxx, yyy, zzz  FROM Table WITH (nolock)'.
    conn := (DBConnection new)
                    dsn: 'DBNAME';
                    uid: 'UNAME';
                    pwd: 'PASSWD';
                    connect.
    query := conn query: sql.
    rows := 0.
    Time millisecondsToRun: [query rawDo: [rows := 1 + rows]]. "--> 42719"

This fetches 121,744 rows in around 43 seconds.  The four selected columns
are all 32-bit integers.

Note that I'm using #rawDo: to try to get a picture of where the time is
really going.

I tried an "equivalent" in Java, running the same query against the same
ODBC datasource, accessed via the ODBC/JDBC bridge (with try/catche blocks
elided):

    Connection conn = DriverManager.getConnection(
        "jdbc:odbc:DBNAME",
        "UNAME",
        "PASSWD");
    Statement query = conn.createStatement();
    String sql = "SELECT www, xxx, yyy, zzz  FROM Table WITH (nolock)";
    ResultSet rs = query.executeQuery(sql);
    long start = System.currentTimeMillis();
    int rows = 0;
    while (rs.next())
     {
        //  int f1 = rs.getInt(1);
        //  int f2 = rs.getInt(2);
        //  int f3 = rs.getInt(3);
        //  int f4 = rs.getInt(4);
        rows++;
     }
     long end = System.currentTimeMillis();
    System.out.println(rows
       + " rows fetched in "
       + ((end - start) / 1000.0)
       + " secs");

(my apologies to anyone who comes out in hives at the sight of naked Java
code...)

That also fetches 121,744 rows, but takes around 0.6 seconds.  If I force
the JVM into interpreted mode only (which I'd expect to be slower than
Dolphin's VM), the time goes up to 2.4 seconds.

The four lines which are commented out are because I'm trying to make the
loop equivalent to #rawDo:, if I put them back in (and so actually pull the
column data out of the returned row), then the time goes up to 1.2 seconds
(or 5.8 in pure interpreted mode).

I should mention that I'm using Java for this comparison only because
that's the only other way I know to talk ODBC to SQL server.

I traced into Dolphin and the buffers seem to be set up and bound correctly
before the main loop starts.  Running under Ian's profiler shows that the
execution time is almost all (>95%) in ODBCLibrary>>sqlExtendedFetch:...  So
I don't think the time is being lost doing data massaging in Dolphin.

Another anomaly is that during the 40-odd second execution, Windows
TaskManager shows that Dolphin is using around 20% of one CPU, and that SQL
server is using around 40% of the other one.  That's odd because the Java
test shows that it can supply the same data to other programs in less than a
second, so what's it doing with all that CPU time when driven from Dolphin ?

I'm not expert in ODBC, nor -- come to that -- in the Database Connection
APIs, but it looks to me as if *something* in the way Dolphin drives ODBC
(presumably the batching factor) is slowing it down by a factor of at least
20 and perhaps as high as 60-70.  Presumably (but I didn't test it) the
effect would be even worse if I'd been going over our LAN to talk to the
server.

Since the real datasets that I was wanting to work with were of the order of
tens or hundreds of millions of rows, that meant that I couldn't use Dolphin
for the task.  (Which was slightly embarrassing since I play the Smalltalk
advocate at work, and it made my frequent comments -- taunts, really -- to
management and other developers like "that would be much easier if we were
using a grown-up language" sound more than a little hollow...)

> Blair

 -- chris


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Bill Schwab
Chris, Blair,

> (my apologies to anyone who comes out in hives at the sight of naked Java
> code...)

Yes, the itching is unbearable :)


> The four lines which are commented out are because I'm trying to make the
> loop equivalent to #rawDo:, if I put them back in (and so actually pull
the
> column data out of the returned row), then the time goes up to 1.2 seconds
> (or 5.8 in pure interpreted mode).
>
> I should mention that I'm using Java for this comparison only because
> that's the only other way I know to talk ODBC to SQL server.
>
> I traced into Dolphin and the buffers seem to be set up and bound
correctly
> before the main loop starts.  Running under Ian's profiler shows that the
> execution time is almost all (>95%) in ODBCLibrary>>sqlExtendedFetch:...
So
> I don't think the time is being lost doing data massaging in Dolphin.

The simplest explanation would be that Dolphin is requesting one record at a
time rather than many as has been suggested (and confirmed??) before.


> Another anomaly is that during the 40-odd second execution, Windows
> TaskManager shows that Dolphin is using around 20% of one CPU, and that
SQL
> server is using around 40% of the other one.  That's odd because the Java
> test shows that it can supply the same data to other programs in less than
a
> second, so what's it doing with all that CPU time when driven from Dolphin
?

Probably unrelated, but, I'll mention it anyway: I have periodically
struggled with a tendency of my Dolphin apps to "stall".  A few of the
problems turned out to be caused by (long since corrected) problems in
critical sections and weak collections.  Of course, many more were deadlocks
in my own code because I bit off too much in a critical section.  I've also
found it "necessary" to change the idle loop.  It's fairly common for my
code to end up with nothing else to do but wait for a socket read stream to
get some more data.  However, I once had two DCOM apps talking and noticed
long pauses in various batch jobs between them.  I "fired" DCOM for other
reasons, and began using sockets for everything that crosses machine
boundaries.

Interestingly, the pauses persisted with sockets.  Blair concluded that the
message loop went to sleep in good faith, and _then_ the data arrived; I
agree with his analysis.  I finally shortened the idle loop's sleep duration
to something more tolerable given the frequency of the problem.  I had a
similar problem on NT4, and finally ended up using my tweaked 9x idle loop
for it too.

Please note that I do a lot of multi-threaded programming, and could easily
have problems in my code.  Deadlocks tend to show themselves fairly easily
(things stop happening), but, if I have some kind of under-protection
problem, then it could be very difficult to track down - hence the very good
advice in the Education Centre to over- rather than under-protect.  It's
also possible that some of my hacks are no longer necessary due to
improvements in Dolphin over time.

Still, I suspect that are some places in which Dolphin does nothing for a
while.  I'm glad to hear about the new VM's addressing Dolphin's excessive
yeilding to Access 97; that might help with Chris' problem, but, I it.
Chris, have you tried the test with Dolphin 2.x?

Ideally and in no particular rush, I'd like to see some kind of (probably
remote) monitor of the VM's activities.  It would probably have to be
filterable to specific Process names (a wildcard capbility would be useful -
I use a lot of threads).  Some things could be documented by exception (e.g.
Process xyz waiting > n seconds).  This probably could (and should) be
prototyped in Smalltalk but, I suspect that to be useful in a misbehaving
app, it would have to be coded into the VM.  Also, it would really need to
be useable in deployed apps, and on any version of Windows.  The remote
client/GUI would be done all in Dolphin.  It might also be enough for the VM
to open an always-on-top window and write status info there, but, a remote
app with logging capability would probably be more useful.  It goes without
saying that there should be no overhead when it's not in use :)  In tradeoff
for zero overhead, I'd be more than willing to register a different VM or
edit registry settings to toggle this capability.


> I'm not expert in ODBC, nor -- come to that -- in the Database Connection
> APIs, but it looks to me as if *something* in the way Dolphin drives ODBC
> (presumably the batching factor) is slowing it down by a factor of at
least
> 20 and perhaps as high as 60-70.  Presumably (but I didn't test it) the
> effect would be even worse if I'd been going over our LAN to talk to the
> server.

Makes sense.


Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Blair McGlashan
In reply to this post by Chris Uppal-3
Chris

You wrote in message
news:[hidden email]...
> ...
> I also reported finding problems with the Database Connection (I mentioned
> them in the original thread).
>
> Since then, I've investigated the problem a little more (but not tried to
> fix it); here are some numbers.
> [...big snip of code and stats...]

Thanks for the research. I would think that the big difference between the
Java code and the Dolphin DB connection is the sort of cursor used. Dolphin
uses a "dynamic" cursor type that allows navigation backwards and forwards
back through the result set. This makes for a great deal of flexibility, but
is a big performance hit. I suspect the Java code is using a "forward-only"
cursor (also sometimes call a firehose cursor) by default, which is very
cheap for the DB to implement, especially for a simple select statement with
no joins. Perhaps someone who has the source (and a stronger stomach than
me) could take a look at it and see what the Java library actually does.

If you install the attached package (which is a quick'n'dirty implementation
of forward-only result sets that doesn't modify any existing DB Connection
methods), and evaluate (modifying your original expression):

     sql := 'SELECT www, xxx, yyy, zzz  FROM Table WITH (nolock)'.
     conn := (DBConnection new)
                     dsn: 'DBNAME';
                     uid: 'UNAME';
                     pwd: 'PASSWD';
                     connect.
     query := conn query: sql forwardOnly: true.
     rows := 0.
     Time millisecondsToRun: [query rawDo: [rows := 1 + rows]].

You should find that it is at least an order of magnitude faster  - in my
experiments in Dolphin 5 against a 100,000 row MS SQL Server 7.0 table the
time to enumerate the entire recordset dropped from 52 seconds to just over
2 (in D4 it went down to about 3.7 seconds). You may also notice that the
initial #query:forwardOnly: runs almost instantaneously, whereas there is a
noticeable pause while #query: executes. Presumably this is due to the
database allocating and initialising the data structures it needs to
implement the dynamic/keyset driven cursor.

Fetching the rows in blocks rather than individually would also help, but
apart from in the remote case, I don't think it is going to make such a
marked difference.

A particularly unfortunate downside of the forward-only cursor is that one
has started navigating through it then it ties up the entire connection
(at least for SQL server), and hence one can't use the same connection for
more than one query at a time. In order to make this workable in conjunction
with the DB Connection one would probably have to look at deliberately
cloning connections for each forward-only result set.

I also experiment with ADO, and having generated the interfaces using the
ActiveX Component Wizard I implemented a #do: like this:

!ADODBRecordset15 methodsFor!

do: operation
 "Evaluate the <monadicValuable> argument, operation, for each of the
 records in the receiver."

 | fields |
 self MoveFirst.
 fields := self fields.
 [self eof] whileFalse: [
  operation value: fields.
  self MoveNext]! !
!ADODBRecordset15 categoriesFor: #do:!enumerating!public! !

I then evaluated:

rs := ADODB_Recordset new.
rs open: 'select * from LotsaRows' activeConnection: 'DSN=LocalServer'.
Time millisecondsToRun: [rs do:[:e | ]].

This isn't quite the same as DBResultSet>>rawDo: (in that the ADO itself is
decoding the data even if Dolphin isn't accessing it) and neither is it
quite like DBResultSet>>do:, because it itsn't actually converting the rows
to objects - in fact if one tried to use this to implement #collect: or
similar, then one would end up with a collection of last row since the
'fields' collection is updated in place as one navigates. Anyway, this runs
through the 100,000 row table in just over 4 seconds. Pulling the data out
into objects is a lot slower than with the DB connection, unfortunately,
mainly because everything has to be transmitted as a VARIANT and decoded.

ADO is, in fact, using a forward-only cursor here, and it doesn't permit
navigation backwards in the result set. If we instead evaluate:

rs := ADODB_Recordset new.
rs cursorType: adOpenKeyset.
rs open: 'select * from LotsaRows' activeConnection: 'DSN=LocalServer'.
Time millisecondsToRun: [rs do:[:e | ]].

This took over 80 seconds on my machine, so it seems to suffer even more
than Dolphin does when using a keyset driven cursor. For a dynamic cursor
(adOpenDynamic) the initial query runs more quickly, and the time drops to
just under 60 seconds. The last I heard, though, using dynamic cursors could
cause problems against Oracle DBs because it implements nothing other than
forward-only read-only cursors, and everything else has to be emulated by
the driver/driver manager and/or ADO itself.

ADO has a lot to be said for it and going forward I think it should become
the database connection mechanism of choice. We have considered modifying
the DB Connection package to use ADO, but unfortunately it doesn't really
"fit" from a design perspective and trying to make it do so would probably
compromise both. There is also some work to do to try and improve the
performance of converting to/from Smalltalk objects. It is likely that we
will ship an "official" ADODB package in the near future, but one can get by
pretty well with the output from the wizard.

Regards

Blair


-------------------------------------------------
| package |
package := Package name: 'DBForwardOnly'.
package paxVersion: 0;
 basicComment: 'Quick and dirty add-on to Dolphin Database Connection that
implements forward-only result sets, which are much faster for large
databases.

Blair McGlashan
Object Arts Ltd.
'.

package basicPackageVersion: ''.

"Add the package scripts"

"Add the class names, loose method names, global names, resource names"
package classNames
 add: #DBForwardOnlyCursor;
 add: #DBForwardOnlyResultSet;
 yourself.

package methodNames
 add: #DBConnection -> #exec:forwardOnly:;
 add: #DBConnection -> #query:forwardOnly:;
 yourself.

package globalNames
 yourself.

package resourceNames
 yourself.

"Binary Global Names"
package binaryGlobalNames: (Set new
 yourself).
"Resource Names"
package allResourceNames: (Set new
 yourself).

"Add the prerequisite names"
package setPrerequisites: (IdentitySet new
 add: 'Database Connection';
 yourself).

package!

"Class Definitions"!

DBResultSet subclass: #DBForwardOnlyResultSet
 instanceVariableNames: 'position'
 classVariableNames: ''
 poolDictionaries: ''
 classInstanceVariableNames: ''!
DBStatement subclass: #DBForwardOnlyCursor
 instanceVariableNames: ''
 classVariableNames: ''
 poolDictionaries: ''
 classInstanceVariableNames: ''!
"Loose Methods"!

!DBConnection methodsFor!

exec: aString forwardOnly: aBoolean
 "Execute the SQL in aString, answering a dynamic or forward-only cursor
 depending on the <boolean> argument."

 | statement |
 statement := (aBoolean ifTrue: [DBForwardOnlyCursor] ifFalse:
[DBStatement]) parent: self.
 statement exec: aString.
 ^statement!

query: aString forwardOnly: aBoolean
 "Execute the SQL in aString.
 Answer a DBResultSet representing the resultant result set.
 If the <boolean> argument is true then the result set will
 support forward-only navigation, but will be substantially
 faster in consequence."

 ^(self exec: aString forwardOnly: aBoolean) results! !
!DBConnection categoriesFor: #exec:forwardOnly:!executing!public! !
!DBConnection categoriesFor: #query:forwardOnly:!executing!public! !

"End of package definition"!



DBForwardOnlyResultSet comment: ''!

DBForwardOnlyResultSet guid: (GUID fromString:
'{BDEB3BCD-B383-4BBB-A02A-E63B31338641}')!

!DBForwardOnlyResultSet categoriesForClass!ODBC Interface! !
!DBForwardOnlyResultSet methodsFor!

at: anInteger
 "Answer the row at index anInteger in the receiver's result set"

 position = anInteger ifFalse: [
  anInteger < 1 ifTrue: [^self errorSubscriptBounds: anInteger].
  position > anInteger ifTrue: [self requery].
  [position < anInteger] whileTrue: [self moveNext isNil ifTrue: [^self
errorSubscriptBounds: anInteger]]].
 ^buffer asObject!

basicFirst
 "Private - Answer the first row of the receiver"

 ^self moveFirst isNil
  ifFalse: [buffer asObject]!

basicLast
 "Private - Answer the last row of the receiver's result set."

 [self moveNext notNil] whileTrue.
 ^position > 0 ifTrue: [buffer asObject]!

basicNext
 "Private - Answer the next row of the receiver's result set"

 ^self moveNext isNil
  ifFalse: [buffer asObject]!

basicPrev
 "Private - Answer the previous row of the receiver's result set.
 Implementation Note: This will be very slow in a large record set since
 we have to start from the beginning again."

 ^self at: position - 1!

bind: anArrayOfColNums
 "Private - Create and bind a buffer to hold the
 specified columns (or #() for all columns)
 as they are fetched from the result set"

 super bind: anArrayOfColNums.
 position := 0.!

moveFirst
 "Private - If not at the start of the result set, then re-exec the
statement."

 ^position == 1
  ifTrue: [0]
  ifFalse: [
   position > 0 ifTrue: [self requery].
   self moveNext]!

moveNext
 "Private - Advance to the next row in the result set."

 | status |
 status  := self xFetch: SQLFetchNext at: 0.
 status notNil ifTrue: [position := position + 1].
 ^status!

next
 "Answer the next row of the receiver's result set"

 ^self basicNext!

prev
 "Answer the previous row of the receiver's result set"

 ^self basicPrev!

rawDo: aZeroArgBlock
 | status |
 status := self moveFirst.
 [status isNil] whileFalse: [
  aZeroArgBlock value.
  status := self moveNext]!

requery
 self statement close.
 position := 0! !
!DBForwardOnlyResultSet categoriesFor: #at:!accessing!public! !
!DBForwardOnlyResultSet categoriesFor: #basicFirst!enumerating!private! !
!DBForwardOnlyResultSet categoriesFor: #basicLast!enumerating!private! !
!DBForwardOnlyResultSet categoriesFor: #basicNext!enumerating!private! !
!DBForwardOnlyResultSet categoriesFor: #basicPrev!enumerating!private! !
!DBForwardOnlyResultSet categoriesFor: #bind:!binding!private! !
!DBForwardOnlyResultSet categoriesFor: #moveFirst!operations!private! !
!DBForwardOnlyResultSet categoriesFor: #moveNext!operations!private! !
!DBForwardOnlyResultSet categoriesFor: #next!enumerating!public! !
!DBForwardOnlyResultSet categoriesFor: #prev!enumerating!public! !
!DBForwardOnlyResultSet categoriesFor: #rawDo:!enumerating!private! !
!DBForwardOnlyResultSet categoriesFor: #requery!operations!private! !



DBForwardOnlyCursor comment: ''!

DBForwardOnlyCursor guid: (GUID fromString:
'{EF6CCEE7-ACDE-44BD-A479-849B0CE671AF}')!

!DBForwardOnlyCursor categoriesForClass!ODBC Interface! !
!DBForwardOnlyCursor methodsFor!

allocatedHandle
 "Private - Answer the receiver's ODBC statement handle, which is lazily
 allocated if necessary."

 handle isNil ifTrue: [
  executed := false.
  handle := parent allocStmtHandle: self.
  self beFinalizable.
  "The default cursor type is forward only, so leave as is"].
 ^handle!

results
 "Answer a DBResultSet that manages the results for the receiver.
 The result set will cause the receiver to be lazily executed when
 any attempt is made to access its contents."

 ^DBForwardOnlyResultSet statement: self.! !
!DBForwardOnlyCursor categoriesFor: #allocatedHandle!accessing!private! !
!DBForwardOnlyCursor categoriesFor: #results!accessing!public! !


"Binary Globals"!

"Resources"!


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Alan Wostenberg-3
In reply to this post by Blair McGlashan
"Blair McGlashan" <[hidden email]> wrote in message news:<9naqcf$6jg75$[hidden email]>...

> > I read notes of 2001-03-12 and wonder if Dolphin is fetching one row
> > at a time so I'm taking a serious network latency hit. Is that
> > possible, if so, how can I set the blocking factor higher?
>
> Yes that is true. Dolphin's DB connection was not designed with remote
> access in mind, and it does request only a single record at a time. If the
> underlying driver is not doing its own batching (I'm surprised it doesn't),
> then that is likely to result in very poor performance against a remote
> database (and personally I would call 4 recs/sec very poor performance). You
> could verify that by comparing performance against a local database.

I compared with VisualWorks Smalltalk ODBCSession, idential query
answering 3600 records from SLQ Server database across the puddle:
Visual Works 5i3 commercial   10 seconds
Dolphin      4.01 trial       790 seconds

VisualWorks ad-hoc query tool lets one set the buffer size to the
driver, I set it at 1 and 10 and observed no difference. So I don't
know what's going on here, except out of the box two orders of
magnitude difference performance.

> Oddly this has (as far as I recall) only come up that once before (in a
> report from Dmitry Zamotkin), and so I while we have an enhancement entry in
> our bug-tracking database to add block fetch support, at the moment there is
> no set timescale for it to be actioned. The priority of any enhancement is
> mainly a commercial decision based on demand, etc, but we are open to
> lobbying and/or specific contractual arrangements :-).

So if Baan funds the work Baan owns it, right<g>. For now I'll locate
the Dolphin image next to the database server and avoid the
Denver-Holland hop. Meanwhile I appeal to your sense of professional
honor.

Match VisualWorks ODBC performance.

-Alan Wostenberg, Baan


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Alan Wostenberg-3
In reply to this post by Blair McGlashan
> If you install the attached package (which is a quick'n'dirty implementation
> of forward-only result sets that doesn't modify any existing DB Connection
> methods), and evaluate sql..

> You should find that it is at least an order of magnitude faster  - in my
> experiments in Dolphin 5 against a 100,000 row MS SQL Server 7.0 table the
> time to enumerate the entire recordset dropped from 52 seconds to just over
> 2 (in D4 it went down to about 3.7 seconds). You may also notice that the
> initial #query:forwardOnly: runs almost instantaneously, whereas there is a
> noticeable pause while #query: executes. Presumably this is due to the
> database allocating and initialising the data structures it needs to
> implement the dynamic/keyset driven cursor.

I applied and the remote access query dropped answering 3700 rows from
771 seconds to 5.4.
 
You just gave us remoters two orders of magnitude performance boost.
WELL DONE BLAIR!

I'm speculating the forward-only cursor enables some sort of buffering
read-ahead to avoid the network latency, so would not bother with
block fetches.

> ADO is, in fact, using a forward-only cursor here, and it doesn't permit
> navigation backwards in the result set. If we instead evaluate:

ADO is strategic according to Rockford Lhotka in his MS Press book "VB
 6 business objects" p118 :

" In general ADO is the preferred data access technology. All of the
other data technologies (RDO, ODBC or ODBCDirect) continue to be
supported, but Microsoft is putting their development efforts entirely
towards improving and enhancing ADO (and OLE DB, its underlying
technology). "

Greatfully,
-Alan Wostenberg, Baan


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Frank Sergeant
In reply to this post by Alan Wostenberg-3
"Alan Wostenberg" <[hidden email]> wrote in message
news:[hidden email]...
> I am using Dolphin 4 trial version to do a concept proof before
> converting over a production Visual Works Smalltalk and several VB
> apps.

Alan, I can understand why you might want to replace VB apps with Dolphin
but what caught my eye was that you plan to convert a VW app to Dolphin.
Would you be willing to discuss the factors involved and what led to your
decision?


-- Frank
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Chris Uppal-3
In reply to this post by Blair McGlashan
Blair,

> I suspect the Java code is using a "forward-only"
> cursor (also sometimes call a firehose cursor) by default, which is very
> cheap for the DB to implement, especially for a simple select statement
with
> no joins. Perhaps someone who has the source (and a stronger stomach than
> me) could take a look at it and see what the Java library actually does.

The code for the JDBC/ODBC bridge doesn't seem to be part of the standard
distribution, but the definition of a java "Connection" object states that:

    Result sets created using the returned Statement object
    will by default have forward-only type and read-only concurrency.

> If you install the attached package [...]
> You should find that it is at least an order of magnitude faster

Brilliant!

Yes, the time dropped to 2.06 seconds (from 43).

BTW, forcing Java to use non-forward only cursors took the Java loop's time
up from 0.6 seconds (1.2 when interpeted) to 25 seconds (30 interpreted).
So that, too, confirms the effect.  There's still a small performance
difference -- not large enough to care about, I'd say -- I suspect it may be
due to the way the Java implementation uses "read-only concurrency" by
default.  I wasn't able to find a way (that worked) to change that, though,
so I can't confirm it.

> A particularly unfortunate downside of the forward-only cursor is that one
> has started navigating through it then it ties up the entire connection
> (at least for SQL server), and hence one can't use the same connection for
> more than one query at a time. In order to make this workable in
conjunction
> with the DB Connection one would probably have to look at deliberately
> cloning connections for each forward-only result set.

Personally, I'd be quite happy just to have the option of using forward-only
cursors and live with (or code around) the restriction.

> ADO has a lot to be said for it and going forward I think it should become
> the database connection mechanism of choice. We have considered modifying
> the DB Connection package to use ADO, but unfortunately it doesn't really
> "fit" from a design perspective and trying to make it do so would probably
> compromise both. There is also some work to do to try and improve the
> performance of converting to/from Smalltalk objects. It is likely that we
> will ship an "official" ADODB package in the near future, but one can get
by
> pretty well with the output from the wizard.

Hmm...  We used ADO originally at my work, but we switched (at considerable
cost in dev time) to ODBC.  I'm not a database man so I'm not sure of the
details, but there were problems with performace (we have databases in the
TerraByte range and up), and thread-friendlyness (I seem to remember being
told that ADO was designed only with VB in mind and doesn't "like" the kind
of unrestricted threading we were doing in C++).   Anyway, I thought OLE-DB
was Microsoft's current recommendation for Real Programmers ?

> Blair

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Alan Wostenberg-3
In reply to this post by Frank Sergeant
"Frank Sergeant" <[hidden email]> wrote in message news:<UUfo7.6486$[hidden email]>...

> "Alan Wostenberg" <[hidden email]> wrote in message
> news:[hidden email]...
> > I am using Dolphin 4 trial version to do a concept proof before
> > converting over a production Visual Works Smalltalk and several VB
> > apps.
>
> Alan, I can understand why you might want to replace VB apps with Dolphin
> but what caught my eye was that you plan to convert a VW app to Dolphin.
> Would you be willing to discuss the factors involved and what led to your
> decision?

Frank, the key factors are lower entry barrier in the Baan shop
because Dolphin's (a) licensing price (b) affinity for MS Windows.

Licensing. I'm looking at our annual VisualWorks renewal due now at
$5,000k/seat the terms of which are renew, or disconnect the live
application. Vs Dolphin under $500 perpetual license. VisualWorks is
great product not ten times the value of Dolphin.

Affinity for MS Windows. Three years ago Baan announced a
Microsoft-centric strategy. Since then any product that is not tightly
tracking relevant Windows technologies suffers a black mark. This is
not only about native widgets look and feel, but also Active-X, ADO,
OLE DB, Visual Source Safe. Plus whatever future Technologies
Microsoft puts forth (like Micorosft.NET). Score for VisualAge and
Dolphin. To your average VB guy Dolphin is less alien than VW which
lets me focus on Smalltalk itself in presentations.

For example, yesterday after Dolphin demos via Netmeeting a technician
asked me "is Smalltalk hard to learn?". I said "no". But years ago I
would have quoted the standard line "it takes about 6 months to come
up to speed but it's worth it". This "It's easy" message I learned not
from Cincom nor IBM but from little Object Arts, and I've come to see
it is true. Smalltalk is as easy as VB only more scalable because of
it's "model first" approach.

If our shop still officially sanctioned Smalltalk and platform
portability, VW price would not be an issue and I would ignored the
others. But one must pick his battles. "Up with Smalltalk" is one I'll
take on at a personal level; "down with Microsoft" is not. Yet.

Baan's Last Smalltalker,
-Alan Wostenberg,


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Frank Sergeant
"Alan Wostenberg" <[hidden email]> wrote in message
news:[hidden email]...

> Frank, the key factors are lower entry barrier in the Baan shop
> because Dolphin's (a) licensing price (b) affinity for MS Windows.

Alan, thanks for discussing these issues.

> Licensing. I'm looking at our annual VisualWorks renewal due now at
> $5,000k/seat the terms of which are renew, or disconnect the live
> application.

I myself have had serious reservations about Cincom's licensing (and public
disclosure of the terms thereof) policies.  At first the way I read the
license (the VAR license) was that Cincom could basically unilaterally
renegotiate the license at their pleasure and also that once you quit paying
you couldn't use the product thereafter, as opposed to say damn near
anything else, such as Delphi or Dolphin where I could still use an older
version I had purchased even if I did not elect to purchase upgrades.  But,
I thought James Robertson tried to clarify that in comp.lang.smalltalk
saying that you *could* continue to use your then-current version of
Smalltalk after you stopped paying, you just wouldn't be entitled to upgrade
to the newer versions.  Any chance that line of reasoning might apply to
you?  *One* of the barriers that Cincom seems to present to *me* is the
confusion and uncertainty and complexity of the licensing.

> Vs Dolphin under $500 perpetual license. VisualWorks is
> great product not ten times the value of Dolphin.

Good point.

> Affinity for MS Windows. Three years ago Baan announced a
> Microsoft-centric strategy. Since then any product that is not tightly
> tracking relevant Windows technologies suffers a black mark.

I swing madly back and forth between hating Windows and MS and merely
disliking them a great deal.  Unfortunately, I think my customers tend to
have a policy (perhaps not as strong or as articulated) similar to Baan's.
Thanks (I guess) for helping to keep me aware of which side of my bread is
buttered.

> Baan's Last Smalltalker,


-- Frank


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Paul Hudson
"Frank Sergeant" <[hidden email]> wrote in
news:sigp7.6924$[hidden email]:

> I swing madly back and forth between hating Windows and MS and merely
> disliking them a great deal.  

Which of the 5 phases are you in?
:-) http://www.develop.com/dbox/cxx/fivephases.htm


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Blair McGlashan
In reply to this post by Alan Wostenberg-3
Alan

You wrote in message news:[hidden email]...
> > If you install the attached package (which is a quick'n'dirty
implementation
> > of forward-only result sets that doesn't modify any existing DB
Connection
> > methods), and evaluate sql..
>
> > You should find that it is at least an order of magnitude faster  - in
my
> > experiments in Dolphin 5 against a 100,000 row MS SQL Server 7.0 table
the
> > time to enumerate the entire recordset dropped from 52 seconds to just
over
> > 2 (in D4 it went down to about 3.7 seconds). You may also notice that
the
> > initial #query:forwardOnly: runs almost instantaneously, whereas there
is a
> > noticeable pause while #query: executes. Presumably this is due to the
> > database allocating and initialising the data structures it needs to
> > implement the dynamic/keyset driven cursor.
>
> I applied and the remote access query dropped answering 3700 rows from
> 771 seconds to 5.4.
>
> You just gave us remoters two orders of magnitude performance boost.
> WELL DONE BLAIR!

I'm glad it helped. A slightly revised implementation of it will appear in
the next release.

With this enhancement, how do you find that performance compares with VB and
VW?

>
> I'm speculating the forward-only cursor enables some sort of buffering
> read-ahead to avoid the network latency, so would not bother with
> block fetches.

Yes, I would think so. Although block fetch would probably buy some
improvement, I doubt it would be as significant.

>
> > ADO is, in fact, using a forward-only cursor here, and it doesn't permit
> > navigation backwards in the result set. If we instead evaluate:
>
> ADO is strategic according to Rockford Lhotka in his MS Press book "VB
>  6 business objects" p118 :
>
> " In general ADO is the preferred data access technology. All of the
> other data technologies (RDO, ODBC or ODBCDirect) continue to be
> supported, but Microsoft is putting their development efforts entirely
> towards improving and enhancing ADO (and OLE DB, its underlying
> technology). "

Yes, that is clear. ADO has a lot going for it, but unfortunately its
orientation toward VB compromises its performance potential in other
languages for which VARIANT is not a (the) native data type. Although OLE DB
doesn't have that problem, it is significantly lower-level abstraction, and
thus way to complex for direct use in a typical application. What would be
nice would be an abstraction like ADO that was more language neutral. That
is not to say that ADO doesn't work perfectly well in Dolphin, its just that
the overhead of the ADO layer converting everything into VARIANTs, and then
Dolphin converting them back again (combined with having to do this
field-by-field) makes the reification of rows much slower than through ODBC.

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Alan Wostenberg-3
> I'm glad it helped. A slightly revised implementation of it will appear in
> the next release.
>
> With this enhancement, how do you find that performance compares with VB and
> VW?

In my remote query speed Dolphin slightly exceeds VisualWorks.
VisualWorks has a memory leak bug in it's ODBC driver precluding 24x7
operation I'm hopping Dolphin doesn't suffer. I don't have
comparisions with VB.

Some very minor downsides:
 - Dolphin's DBConnection>>tables method crawls and presumably would
benefit from the technique.
 - I assume for production you fixed the bug in DBResultSet>>do: which
throws throws a walkback when zero results.
 - Unlike VW, Dolphin UI is nonresponsive during these tight ODBC
iterators over the WAN - not even a polite hourglass, and tracing to
the Transcript from the iteration loop is kind of herky-jerky.
 - I did find the DBResultSet>>size method takes as long as the query
itself, a characteristic I don't recall from VisualWorks. So progress
bars on long queries, I found it best to do a sql COUNT() to first get
the size to initialize progress bar, then reissue full query to fetch
results. row by row.

These are minor and overall Dolphin works just fine over the WAN with
the fix.

-Alan


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Frank Sergeant
In reply to this post by Paul Hudson
"Paul Hudson" <[hidden email]> wrote in message
news:Xns911FBE939FDE7phudsonpoboxcom@127.0.0.1...
> "Frank Sergeant" <[hidden email]> wrote in
> news:sigp7.6924$[hidden email]:
>
> > I swing madly back and forth between hating Windows and MS and merely
> > disliking them a great deal.
>
> :-) http://www.develop.com/dbox/cxx/fivephases.htm

Thanks for the humor.

> Which of the 5 phases are you in?

I certainly recognized some of the aspects of some of the phases but I am
not quite prepared to let the enemy define the matter quite so
simplistically <wink>.


-- Frank
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: ODBC overseas performance problem

Blair McGlashan
In reply to this post by Alan Wostenberg-3
Alan

"Alan Wostenberg" <[hidden email]> wrote in message
news:[hidden email]...
> > I'm glad it helped. A slightly revised implementation of it will appear
in
> > the next release.
> >
> > With this enhancement, how do you find that performance compares with VB
and
> > VW?
>
> In my remote query speed Dolphin slightly exceeds VisualWorks.
> VisualWorks has a memory leak bug in it's ODBC driver precluding 24x7
> operation I'm hopping Dolphin doesn't suffer. ...

I'd imagine that will depend on whether the leak is in VW code, or the ODBC
driver itself. In the past we have found significant leaks in ODBC drivers,
particularly the Oracle ones. If the ODBC driver (or driver manager) leaks,
then it probably won't matter which client you use, unless it results from
the particular sequence of calls made by that client.

>...I don't have
> comparisions with VB.
>
> Some very minor downsides:
>  - Dolphin's DBConnection>>tables method crawls and presumably would
> benefit from the technique.

Possibly. Its a direct invocation of SQLTables(), so I can't think of any
other thing that Dolphin is doing that would add significant overhead to the
underlying API call. All of the schema statements have been modified to use
forward-only cursors for the next release, but I have no figures as to how
this affects the performance of querying the schema.

>  - I assume for production you fixed the bug in DBResultSet>>do: which
> throws throws a walkback when zero results.

Are we talking about a bug in the original or extended DB Connection
packages?

>  - Unlike VW, Dolphin UI is nonresponsive during these tight ODBC
> iterators over the WAN - not even a polite hourglass, and tracing to
> the Transcript from the iteration loop is kind of herky-jerky.

I don't know how it is implemented in VW, for example whether it has code
built into the VM or whether it is doing calls through DLL-C Connect. Either
way VW might be using "threaded" calls, an option that could be used in
Dolphin but which was not available when the DB Connection package was
originally written. There is a trade off, however, since using overlapped
calls (Dolphin's name for calls that are run on a thread other than the main
VM thread so that they do not block everything) is less efficient, and one
probably wouldn't want to introduce extra overhead for all cases, so the
best approach would probably be to use a bit of polymorphism to allow a
choice between non-blocking or blocking calls when querying and enumerating
a result set.

Dolphin doesn't display a wait cursor automatically, because that isn't done
by the VM, but in Smalltalk. If you are going to perform a long running
operation, you can wrap it up like this:
    Cursor wait showWhile: [...long running op...]

All processing initiated by UI commands is run inside such a block by
default, but at other times .

Output to the Transcript is not visible until you #flush it, or do certain
other operations such as #cr (which itself sends #flush). Also it is
dependent on the UI process being able to process paint messages from
Windows, which may not happen that regularly when one is in a tight loop. If
#flush alone doesn't help, it is possible to synchronously paint views by
sending them a #update message.

>  - I did find the DBResultSet>>size method takes as long as the query
> itself, a characteristic I don't recall from VisualWorks. So progress
> bars on long queries, I found it best to do a sql COUNT() to first get
> the size to initialize progress bar, then reissue full query to fetch
> results. row by row.

That's right. As the method comment mentions, often the driver is not able
to report the size of a query because the database itself does not report it
back. If you do a 'select * from X', then usually the DBMS will report the
number of rows, since presumably it has that information readily to hand. If
however the query is more complex then depending on the method it uses to
build the result set, it may not know the number of results in advance. In
those cases the SQLRowCount() function to return -1, and Dolphin has to
calculate the size by enumerating the entire result set. It is a good idea
to avoid using #size, and instead write one's code using dynamic
collections, etc, which is in fact what DBResultSet itself does in order to
make if function more efficiently as a subclass of SequenceableCollection.

The same really applies to the use of 'SELECT COUNT(...' as well, since the
DBMS itself may need to enumerate the entire result set in order to
calculate the number of rows (though that depends very much on the query,
one can look at the execution plan to see exactly what it will need to do).
Of course this will be faster, since it takes place in the DBMS itself, but
may still involve a great deal of computation, so if you don't really need
the exact size up front it would be better not to request it. On the other
hand you may have no other option for a progress dialog if there is no way
to make a reasonable guess.

> These are minor and overall Dolphin works just fine over the WAN with
> the fix.

Good.

Regards

Blair