OODB Storage Options and Performance
Daniel Salama
dsalama at user.net
Tue Apr 12 18:58:16 UTC 2005
It's me again :)
I'm not here to put down any storage option available. I just wanted to
share with you guys another little experiment I did with GOODS,
OmniBase, Magma, MySQL, and MySQL with RubyOnRails.
The test consisted of an extremely simplistic process of updating a
sequence number in a dictionary. In a typical CRM-like application, I
would use something like this in order to "generate" a customer ID
number for new customers (unless someone has a better suggestion). In
essence, the test updates a single dictionary element (a counter) 1000
times. I'm sure the code could be optimized so I'm open to suggestions
on how to do so.
My intentions here were not really to compare an OODB against a RDB.
You may decide to ignore the MySQL results.
The GOODS code looked like this:
time:= Time millisecondsToRun:
[Transcript cr..
db := KKDatabase onHost: 'localhost' port: 6100.
db root at: 'Sequences' put: (Dictionary new).
db commit.
base := db root at: 'Sequences'.
nextCustomerNo := base at: 'CustomerNo' ifAbsent: [0].
[0 to: 999 do:
[:i|
(i \\ 100) = 0 ifTrue: [Transcript show: '.'].
nextCustomerNo := nextCustomerNo + 1.
base at: 'CustomerNo' put: nextCustomerNo.
db commit]] ensure: [db logout]].
Transcript cr; show: (time/1000) asFloat; show: ' seconds'.
db := KKDatabase onHost: 'localhost' port: 6100.
base := db root at: 'Sequences'.
Transcript cr; show: 'Last Customer No: '; show: (base at:
'CustomerNo').
db logout.
------------------------------------------------------------------------
------------
The OmniBase code looked like this:
time:= Time millisecondsToRun:
[Transcript cr..
db := OmniBase openOn: 'Macintosh HD:Users:dsalama:OB'.
[OmniBase root at: 'Sequences' put: (Dictionary new)]
evaluateAndCommitIn: db newTransaction.
[base := OmniBase root at: 'Sequences'.
base at: 'CustomerNo' put: 0.
base markDirty.
] evaluateAndCommitIn: db newTransaction.
[0 to: 999 do:
[:i|
(i \\ 100) = 0 ifTrue: [Transcript show: '.'].
[base := OmniBase root at: 'Sequences'.
nextCustomerNo := (base at: 'CustomerNo') + 1.
base at: 'CustomerNo' put: nextCustomerNo.
base markDirty] evaluateAndCommitIn: db newTransaction.
]] ensure: [db close]].
Transcript cr; show: (time/1000) asFloat; show: ' seconds'.
db := OmniBase openOn: 'Macintosh HD:Users:dsalama:OB'.
base := (db newTransaction) root at: 'Sequences'.
Transcript cr; show: 'Last Customer No: '; show: (base at:
'CustomerNo').
db close.
------------------------------------------------------------------------
------------
The Magma code looked like this:
time:= Time millisecondsToRun:
[Transcript cr..
db := MagmaSession hostAddress: #(127 0 0 1) asByteArray port: 51969.
db connectAs: 'dsalama'.
db commit:
[db root at: 'Sequences' put: (Dictionary new)].
base := db root at: 'Sequences'.
db commit:
[base at: 'CustomerNo' put: 0].
[0 to: 999 do:
[:i|
(i \\ 100) = 0 ifTrue: [Transcript show: '.'].
base := db root at: 'Sequences'.
nextCustomerNo := (base at: 'CustomerNo') + 1.
db commit: [base at: 'CustomerNo' put: nextCustomerNo].
]] ensure: [db disconnect]].
Transcript cr; show: (time/1000) asFloat; show: ' seconds'.
db := MagmaSession hostAddress: #(127 0 0 1) asByteArray port: 51969.
db connectAs: 'dsalama'.
base := db root at: 'Sequences'.
Transcript cr; show: 'Last Customer No: '; show: (base at:
'CustomerNo').
db disconnect.
------------------------------------------------------------------------
------------
The MySQL code looked like this:
time:= Time millisecondsToRun:
[Transcript cr..
Socket initializeNetwork.
spec := (JdmConnectionSpec new initialize
user: 'master'; password: 'secret';
host: (NetNameResolver addressForName: 'localhost');
database: 'dcm'; port: 3306).
connection := JdmConnection on: spec.
statement := connection createStatement.
resultSet := connection createStatement executeQuery: 'insert into
tests values (null, ''CustomerNo'', 0)'.
0 to: 999 do:
[:i|
(i \\ 100) = 0 ifTrue: [Transcript show: '.'].
connection := JdmConnection on: spec.
resultSet := connection createStatement executeQuery: 'select next
from tests where sequence = ''CustomerNo'''.
resultSet next.
nextCustomerNo := (resultSet valueNamed: 'next') + 1.
connection close.
[connection := JdmConnection on: spec.
updateSQL := 'update tests set next = ', (nextCustomerNo asString), '
where id = 1'.
connection createStatement executeQuery: updateSQL]
ensure: [connection close]]].
Transcript cr; show: (time/1000) asFloat; show: ' seconds'.
connection := JdmConnection on: spec.
statement := connection createStatement.
resultSet := statement executeQuery: 'select next from tests where
sequence = ''CustomerNo'''.
resultSet next.
nextCustomerNo := (resultSet valueNamed: 'next').
Transcript cr; show: 'Last Customer No: '; show: nextCustomerNo.
connection close.
Granted, that after Alan and Boris explained to me the "limitation" of
the MySQL driver, there is additional overhead in opening and closing
the connection 1000 times.
------------------------------------------------------------------------
------------
And the RubyOnRails code looked like this:
require 'test'
t0 = Time.now
0.upto(999) do |i|
puts "." if (i % 100) == 0
t = Test.find_by_sequence('CustomerNo')
unless t
t = Test.new
t.sequence = 'CustomerNo'
t.next = 0
end
t.next += 1
t.save
end
t1 = Time.now
puts (t1-t0).to_s + ' seconds'
puts "Last Customer No: " +
Test.find_by_sequence('CustomerNo').next.to_s
------------------------------------------------------------------------
------------
The tests were performed on a Powerbook G4 1.5GHz with 1GB RAM with
Squeak 3.7-5989-full with the latest(?) versions of the respective
class libraries.
GOODS: 201.553 seconds
Omnibase: 3.102 seconds
Magma: 73.578 seconds
MySQL: 13.815 seconds
RubyOnRails: 12.411535 seconds
Interestingly the MySQL results were not much better (or worse),
whether you use Squeak or RubyOnRails. It's simply a point of
comparison for the other tests.
I was definitely impressed with OmniBase's performance. As I had said
in previous postings, OB has provided me the best performance so far
during my tests and every day I feel more confident in OB. Also, as I
mentioned in the past, I am now getting ready to purchase a commercial
license for it and hope to get the Linux file locking support from Avi
as well. Also, I hope my move towards purchasing a license motivates
others (e.g. Cees de Groot) to help David support and maintain OB. I
also wish there was better documentation for it.
I was a bit disappointed at the performance of GOODS. I like the GOODS
server and the people I have talked with regarding its performance
under "heavier" loads are very happy with it. Again, as I mentioned in
previous postings, they are not using Smalltalk. They are using Java or
C. As Avi said, it could be a performance tuning issue with the Squeak
GOODS classes and hopefully that would improve over time.
Now, I hope my findings are useful to others. However, I would love to
hear feedback from others regarding this. I tried to make these as
equal and unbiased as possible. Also, the fact that I'm new to all this
may affect the quality and optimization of my code.
Thanks,
Daniel
Daniel Salama
dsalama at user.net
Voice: (954) 655-8051
Fax : (954) 252-3988
------------------------
This e-mail contains information which may be confidential and
privileged. Unless you are the addressee (or authorized to
receive for the addressee), you may not use, copy or disclose
to anyone the message or any information contained in the
message. If you have received the message in error, please
advise the sender by reply e-mail to dsalama at user.net or
tel. +1-954-655-8051 and delete the material from any computer.
More information about the Squeak-dev
mailing list
|