--- benchmark_storm.py 2007-12-23 19:40:56.000000000 -0500 +++ benchmark_sqla_orm.py 2007-12-23 20:25:00.000000000 -0500 @@ -1,94 +1,73 @@ -"""Benchmark for Storm. +"""Benchmark for SQLAlchemy. -Note that the original test omitted the 'step 7 multiview' test which was incomplete, -so its omitted here as well. +Note that test 7 is omitted because the corresponding Storm test was not +completed by Robert Brewer. """ import datetime import os -thisdir = os.path.dirname(__file__) import sys import time -import storm -from storm.locals import * - - -class Zoo(object): - __storm_table__ = 'Zoo' - ID = Int(primary=True, default=storm.expr.Sequence('Zoo_ID_seq')) - Name = Unicode() - Founded = Date() - Opens = Time() - LastEscape = DateTime() - Admission = Float() - - def __init__(self, **kwargs): - for k, v in kwargs.iteritems(): - setattr(self, k, v) - - -class Animal(object): - __storm_table__ = 'Animal' - ID = Int(primary=True, default=storm.expr.Sequence('Animal_ID_seq')) - ZooID = Int() - zoo = Reference(ZooID, Zoo.ID) - Name = Unicode() - Species = Unicode() - Legs = Int(default=4) - LastEscape = DateTime() - Lifespan = Float() - MotherID = Int() -## mother = Reference(MotherID, Animal.ID) - PreferredFoodID = Int() - AlternateFoodID = Int() - - def __init__(self, **kwargs): - for k, v in kwargs.iteritems(): - setattr(self, k, v) - +from sqlalchemy import * +from sqlalchemy.orm import * class ZooMark(object): def setup(self, uri, iterations): - global db, store, ITERATIONS + global db, metadata, ITERATIONS, session - db = create_database('postgres://scott:tiger@127.0.0.1/test') + db = create_engine(uri) - store = Store(db) + metadata = MetaData(db) ITERATIONS = iterations + session = create_session(transactional=True, autoflush=True, bind=db.connect()) def teardown(self): - store.close() - conn = db.connect() - conn._raw_connection.set_isolation_level(0) - conn.raw_execute("DROP TABLE Animal", None) - conn.raw_execute("DROP TABLE Zoo", None) - conn.raw_execute("DROP SEQUENCE Animal_ID_seq", None) - conn.raw_execute("DROP SEQUENCE Zoo_ID_seq", None) - conn.close() + session.close() + metadata.drop_all() + db.dispose() def step_1_create_tables(self): - # Storm doesn't do CREATE TABLE, etc for you - conn = db.connect() - conn._raw_connection.set_isolation_level(0) - conn.raw_execute('CREATE SEQUENCE Animal_ID_seq START 1;', None) - conn.raw_execute('CREATE TABLE Animal (MotherID INT4, LastEscape TIMESTAMP, ' - 'Name VARCHAR(100), ZooID INT4, Age INTERVAL(53), ' - 'PreferredFoodID INT4, Lifespan FLOAT4, ' - """ID INT4 DEFAULT nextval('Animal_ID_seq'), """ - 'AlternateFoodID INT4, PreviousZoos TEXT, ' - 'Legs INT4 DEFAULT 4, Species VARCHAR(100), ' - 'PRIMARY KEY (ID));', None) - conn.raw_execute('CREATE INDEX iAnimalZooID ON Animal (ZooID);', None) - conn.raw_execute('CREATE SEQUENCE Zoo_ID_seq START 1;', None) - conn.raw_execute('CREATE TABLE Zoo (Name VARCHAR(255), Admission DECIMAL(6, 2), ' - 'Founded DATE, LastEscape TIMESTAMP, ' - '''ID INT4 DEFAULT nextval('Zoo_ID_seq'), ''' - 'Opens TIME, PRIMARY KEY (ID));', None) - conn.raw_execute('CREATE INDEX iZooID ON Zoo (ID);', None) - conn.close() + + + global zoo, animal + + zoo = Table('Zoo', metadata, + Column('ID', Integer, Sequence('zoo_id_seq'), primary_key=True, index=True), + Column('Name', Unicode(255)), + Column('Founded', Date), + Column('Opens', Time), + Column('LastEscape', DateTime), + Column('Admission', Float), + ) + zoo.create() + animal = Table('Animal', metadata, + Column('ID', Integer, Sequence('animal_id_seq'), primary_key=True), + Column('ZooID', Integer, ForeignKey('Zoo.ID'), index=True), + Column('Name', Unicode(100)), + Column('Species', Unicode(100)), + Column('Legs', Integer, default=4), + Column('LastEscape', DateTime), + Column('Lifespan', Float(4)), + Column('MotherID', Integer, ForeignKey('Animal.ID')), + Column('PreferredFoodID', Integer), + Column('AlternateFoodID', Integer), + ) + animal.create() + + global Zoo, Animal + class Zoo(object): + def __init__(self, **kwargs): + for k, v in kwargs.iteritems(): + setattr(self, k, v) + class Animal(object): + def __init__(self, **kwargs): + for k, v in kwargs.iteritems(): + setattr(self, k, v) + mapper(Zoo, zoo) + mapper(Animal, animal) def step_1a_populate(self): wap = Zoo(Name=u'Wild Animal Park', @@ -97,9 +76,9 @@ # AdapterFromADO needs to correct. Opens=datetime.time(8, 15, 59), LastEscape=datetime.datetime(2004, 7, 29, 5, 6, 7), - Admission=4.95) - store.add(wap) - + Admission=4.95, + ) + session.save(wap) sdz = Zoo(Name = u'San Diego Zoo', # This early date should play havoc with a number # of implementations. @@ -107,17 +86,19 @@ Opens = datetime.time(9, 0, 0), Admission = 0, ) - store.add(sdz) + session.save(sdz) - bio = Zoo(Name = u'Montr\xe9al Biod\xf4me', + bio = Zoo( + Name = u'Montr\xe9al Biod\xf4me', Founded = datetime.date(1992, 6, 19), Opens = datetime.time(9, 0, 0), Admission = 11.75, ) - store.add(bio) + session.save(bio) - seaworld = Zoo(Name = u'Sea_World', Admission = 60) - store.add(seaworld) + seaworld = Zoo( + Name =u'Sea_World', Admission = 60) + session.save(seaworld) # Let's add a crazy futuristic Zoo to test large date values. lp = Zoo(Name = u'Luna Park', @@ -125,117 +106,102 @@ Opens = datetime.time(0, 0, 0), Admission = 134.95, ) - store.add(lp) - store.flush() + session.save(lp) + session.flush() # Animals leopard = Animal(Species=u'Leopard', Lifespan=73.5,) - store.add(leopard) + session.save(leopard) leopard.ZooID = wap.ID leopard.LastEscape = datetime.datetime(2004, 12, 21, 8, 15, 0, 999907) - store.add(Animal(Species=u'Lion', ZooID=wap.ID)) - store.add(Animal(Species=u'Slug', Legs=1, Lifespan=.75)) - store.add(Animal(Species=u'Tiger', ZooID=sdz.ID)) + session.save(Animal(Species=u'Lion', ZooID=wap.ID)) + session.save(Animal(Species=u'Slug', Legs=1, Lifespan=.75)) + session.save(Animal(Species=u'Tiger', ZooID=sdz.ID)) # Override Legs.default with itself just to make sure it works. - store.add(Animal(Species=u'Bear', Legs=4)) - store.add(Animal(Species=u'Ostrich', Legs=2, Lifespan=103.2)) - store.add(Animal(Species=u'Centipede', Legs=100)) + session.save(Animal(Species=u'Bear', Legs=4)) + session.save(Animal(Species=u'Ostrich', Legs=2, Lifespan=103.2)) + session.save(Animal(Species=u'Centipede', Legs=100)) - store.add(Animal(Species=u'Emperor Penguin', Legs=2, ZooID=seaworld.ID)) - store.add(Animal(Species=u'Adelie Penguin', Legs=2, ZooID=seaworld.ID)) + session.save(Animal(Species=u'Emperor Penguin', Legs=2, ZooID=seaworld.ID)) + session.save(Animal(Species=u'Adelie Penguin', Legs=2, ZooID=seaworld.ID)) - store.add(Animal(Species=u'Millipede', Legs=1000000, ZooID=sdz.ID)) + session.save(Animal(Species=u'Millipede', Legs=1000000, ZooID=sdz.ID)) # Add a mother and child to test relationships - bai_yun = Animal(Species=u'Ape', Nameu='Bai Yun', Legs=2) - store.add(bai_yun) - store.add(Animal(Species=u'Ape', Name=u'Hua Mei', Legs=2, + bai_yun = Animal(Species=u'Ape', Nameu=u'Bai Yun', Legs=2) + session.save(bai_yun) + session.save(Animal(Species=u'Ape', Name=u'Hua Mei', Legs=2, MotherID=bai_yun.ID)) - store.flush() - store.commit() + session.flush() + session.commit() def step_2_insert(self): for x in xrange(ITERATIONS): - store.add(Animal(Species=u'Tick', Name=u'Tick %d' % x, Legs=8)) - - # add flush() so that SQL is actually emitted. otherwise, - # no SQL is emitted in this step (it occurs at the start of step 3). - # adding store.flush() raises the time for 100 iterations from .02 seconds - # to .11 seconds - store.flush() + session.save(Animal(Species=u'Tick', Name=u'Tick %d' % x, Legs=8)) + session.flush() def step_3_Properties(self): - # use list(store.find(...)) so that the SQL is actually emitted. - # otherwise, no SQL is emitted in this step. - # adding list() raises the time for 100 iterations from .02 seconds (assuming flush() in step 2) - # to 1.5 seconds for x in xrange(ITERATIONS): # Zoos - WAP = list(store.find(Zoo, Zoo.Name==u'Wild Animal Park')) - SDZ = list(store.find(Zoo, Zoo.Founded==datetime.date(1835, 9, 13))) - Biodome = list(store.find(Zoo, Zoo.Name==u'Montr\xe9al Biod\xf4me')) - seaworld = list(store.find(Zoo, Zoo.Admission == float(60))) + WAP = list(session.query(Zoo).filter(Zoo.Name==u'Wild Animal Park')) + SDZ = list(session.query(Zoo).filter(Zoo.Founded==datetime.date(1835, 9, 13))) + Biodome = list(session.query(Zoo).filter(Zoo.Name==u'Montr\xe9al Biod\xf4me')) + seaworld = list(session.query(Zoo).filter(Zoo.Admission == float(60))) # Animals - leopard = list(store.find(Animal, Animal.Species == u'Leopard')) - ostrich = list(store.find(Animal, Animal.Species==u'Ostrich')) - millipede = list(store.find(Animal, Animal.Legs==1000000)) - ticks = list(store.find(Animal, Animal.Species==u'Tick')) + leopard = list(session.query(Animal).filter(Animal.Species == u'Leopard')) + ostrich = list(session.query(Animal).filter(Animal.Species==u'Ostrich')) + millipede = list(session.query(Animal).filter(Animal.Legs==1000000)) + ticks = list(session.query(Animal).filter(Animal.Species==u'Tick')) def step_4_Expressions(self): for x in xrange(ITERATIONS): - assert len(list(store.find(Zoo))) == 5 - assert len(list(store.find(Animal))) == ITERATIONS + 12 - assert len(list(store.find(Animal, Animal.Legs==4))) == 4 - assert len(list(store.find(Animal, Animal.Legs == 2))) == 5 - assert len(list(store.find(Animal, Animal.Legs >= 2, Animal.Legs < 20))) == ITERATIONS + 9 - assert len(list(store.find(Animal, Animal.Legs > 10))) == 2 - assert len(list(store.find(Animal, Animal.Lifespan > 70))) == 2 - assert len(list(store.find(Animal, Animal.Species.like(u'L%')))) == 2 - assert len(list(store.find(Animal, Animal.Species.like(u'%pede')))) == 2 + assert len(list(session.query(Zoo))) == 5 + assert len(list(session.query(Animal))) == ITERATIONS + 12 + assert len(list(session.query(Animal).filter(Animal.Legs==4))) == 4 + assert len(list(session.query(Animal).filter(Animal.Legs == 2))) == 5 + assert len(list(session.query(Animal).filter(and_(Animal.Legs >= 2, Animal.Legs < 20)))) == ITERATIONS + 9 + assert len(list(session.query(Animal).filter(Animal.Legs > 10))) == 2 + assert len(list(session.query(Animal).filter(Animal.Lifespan > 70))) == 2 + assert len(list(session.query(Animal).filter(Animal.Species.like(u'L%')))) == 2 + assert len(list(session.query(Animal).filter(Animal.Species.like(u'%pede')))) == 2 - assert len(list(store.find(Animal, Animal.LastEscape != None))) == 1 - assert len(list(store.find(Animal, Animal.LastEscape == None))) == ITERATIONS + 11 + assert len(list(session.query(Animal).filter(Animal.LastEscape != None))) == 1 + assert len(list(session.query(Animal).filter(Animal.LastEscape == None))) == ITERATIONS + 11 # In operator (containedby) - assert len(list(store.find(Animal, Animal.Species.like(u'%pede%')))) == 2 - assert len(list(store.find(Animal, - Animal.Species.is_in((u'Lion', u'Tiger', u'Bear'))))) == 3 + assert len(list(session.query(Animal).filter(Animal.Species.like(u'%pede%')))) == 2 + assert len(list(session.query(Animal).filter( + Animal.Species.in_((u'Lion', u'Tiger', u'Bear'))))) == 3 # Try In with cell references class thing(object): pass pet, pet2 = thing(), thing() pet.Name, pet2.Name = u'Slug', u'Ostrich' - assert len(list(store.find(Animal, Animal.Species.is_in((pet.Name, pet2.Name))))) == 2 + assert len(list(session.query(Animal).filter(Animal.Species.in_((pet.Name, pet2.Name))))) == 2 # logic and other functions - class LENGTH(storm.expr.NamedFunc): - name = "LENGTH" - name = 'Lion' - assert len(list(store.find(Animal, LENGTH(Animal.Species) == len(name)))) == ITERATIONS + 3 + name =u'Lion' + assert len(list(session.query(Animal).filter(func.length(Animal.Species) == len(name)))) == ITERATIONS + 3 - assert len(list(store.find(Animal, Animal.Species.like(u'%i%')))) == ITERATIONS + 7 + assert len(list(session.query(Animal).filter(Animal.Species.like(u'%i%')))) == ITERATIONS + 7 # Test now(), today(), year(), month(), day() - class NOW(storm.expr.NamedFunc): - name = "now" - assert len(list(store.find(Zoo, Zoo.Founded != None, Zoo.Founded < NOW()))) == 3 - assert len(list(store.find(Animal, Animal.LastEscape == NOW()))) == 0 - class date_part(storm.expr.NamedFunc): - name = "date_part" - assert len(list(store.find(Animal, date_part('year', Animal.LastEscape) == 2004))) == 1 - assert len(list(store.find(Animal, date_part('month', Animal.LastEscape) == 12))) == 1 - assert len(list(store.find(Animal, date_part('day', Animal.LastEscape) == 21))) == 1 + assert len(list(session.query(Zoo).filter(and_(Zoo.Founded != None, Zoo.Founded < func.now())))) == 3 + assert len(list(session.query(Animal).filter(Animal.LastEscape == func.now()))) == 0 + assert len(list(session.query(Animal).filter(func.date_part('year', Animal.LastEscape) == 2004))) == 1 + assert len(list(session.query(Animal).filter(func.date_part('month', Animal.LastEscape) == 12))) == 1 + assert len(list(session.query(Animal).filter(func.date_part('day', Animal.LastEscape) == 21))) == 1 def step_5_Aggregates(self): def getall(*args, **kwargs): - return store.execute(Select(*args, **kwargs)).get_all() + return session.connection().execute(select(*args, **kwargs)).fetchall() for x in xrange(ITERATIONS): # views - legs = getall(Animal.Legs) + legs = getall([animal.c.Legs]) legs.sort() expected = {u'Leopard': 73.5, @@ -251,43 +217,40 @@ u'Ape': None, u'Tick': None, } - for species, lifespan in getall([Animal.Species, Animal.Lifespan]): + for species, lifespan in getall([animal.c.Species, animal.c.Lifespan]): assert lifespan == expected[species] expected = [u'Montr\xe9al Biod\xf4me', u'Wild Animal Park'] - # changed "datetime.now()" to be "date.today()" to provide type - # consistency (other platforms require it) - e = getall([Zoo.Name], storm.expr.And(Zoo.Founded != None, - Zoo.Founded <= datetime.date.today(), - Zoo.Founded >= datetime.date(1990, 1, 1))) + e = getall([Zoo.Name], and_(zoo.c.Founded != None, + zoo.c.Founded <= datetime.datetime.now(), + zoo.c.Founded >= datetime.date(1990, 1, 1))) values = [val[0] for val in e] assert set(values) == set(expected) # distinct - legs = [x[0] for x in getall([Animal.Legs], distinct=True)] + legs = [x[0] for x in getall([animal.c.Legs], distinct=True)] legs.sort() def step_6_Editing(self): for x in xrange(ITERATIONS): # Edit - SDZ = store.find(Zoo, Zoo.Name==u'San Diego Zoo')[0] - store.find(Zoo, Zoo.ID==SDZ.ID).set( - Name=u'The San Diego Zoo', - Founded = datetime.date(1900, 1, 1), - Opens = datetime.time(7, 30, 0), - Admission = 35.00) + SDZ = session.query(Zoo).filter(Zoo.Name==u'San Diego Zoo').one() + SDZ.Name = u'The San Diego Zoo' + SDZ.Founded = datetime.date(1900, 1, 1) + SDZ.Opens = datetime.time(7, 30, 0) + SDZ.Admission = 35.00 # Test edits - SDZ = store.find(Zoo, Zoo.Name==u'The San Diego Zoo')[0] + SDZ = session.query(Zoo).filter(Zoo.Name==u'The San Diego Zoo').one() assert SDZ.Founded == datetime.date(1900, 1, 1), SDZ.Founded # Change it back - store.find(Zoo, Zoo.ID==SDZ.ID).set( - Name = u'San Diego Zoo', - Founded = datetime.date(1835, 9, 13), - Opens = datetime.time(9, 0, 0), - Admission = 0) + SDZ.Name = u'San Diego Zoo' + SDZ.Founded = datetime.date(1835, 9, 13) + SDZ.Opens = datetime.time(9, 0, 0) + SDZ.Admission = 0 # Test re-edits - SDZ = store.find(Zoo, Zoo.Name==u'San Diego Zoo')[0] + SDZ = session.query(Zoo).filter(Zoo.Name==u'San Diego Zoo').one() assert SDZ.Founded == datetime.date(1835, 9, 13), SDZ.Founded +