diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-08-02 17:37:59 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-08-02 17:37:59 -0400 |
commit | 7f9becf3fbbdb33d2a9098098d240c25c0afc106 (patch) | |
tree | 3383be863a1eef35d48bab6f0dab10445f42a773 | |
parent | 58b4b8890786b4684fdff217b2ce7fd89b0bf113 (diff) | |
download | sqlalchemy-7f9becf3fbbdb33d2a9098098d240c25c0afc106.tar.gz |
rework the test here to suit 0.8/0.9 mostly, include time tests
-rw-r--r-- | test/perf/orm2010.py | 180 |
1 files changed, 86 insertions, 94 deletions
diff --git a/test/perf/orm2010.py b/test/perf/orm2010.py index 937e6ddff..4f36551c0 100644 --- a/test/perf/orm2010.py +++ b/test/perf/orm2010.py @@ -1,7 +1,7 @@ -# monkeypatch the "cdecimal" library in. -# this is a drop-in replacement for "decimal". -# All SQLA versions support cdecimal except -# for the MS-SQL dialect, which is fixed in 0.7 +import warnings +warnings.filterwarnings("ignore", r".*Decimal objects natively") + +# speed up cdecimal if available try: import cdecimal import sys @@ -13,11 +13,7 @@ from sqlalchemy import __version__ from sqlalchemy import Column, Integer, create_engine, ForeignKey, \ String, Numeric -if __version__ < "0.6": - from sqlalchemy.orm.session import Session - from sqlalchemy.orm import relation as relationship -else: - from sqlalchemy.orm import Session, relationship +from sqlalchemy.orm import Session, relationship from sqlalchemy.ext.declarative import declarative_base import random @@ -33,7 +29,7 @@ class Employee(Base): name = Column(String(100), nullable=False) type = Column(String(50), nullable=False) - __mapper_args__ = {'polymorphic_on':type} + __mapper_args__ = {'polymorphic_on': type} class Boss(Employee): __tablename__ = 'boss' @@ -41,7 +37,7 @@ class Boss(Employee): id = Column(Integer, ForeignKey('employee.id'), primary_key=True) golf_average = Column(Numeric) - __mapper_args__ = {'polymorphic_identity':'boss'} + __mapper_args__ = {'polymorphic_identity': 'boss'} class Grunt(Employee): __tablename__ = 'grunt' @@ -51,32 +47,10 @@ class Grunt(Employee): employer_id = Column(Integer, ForeignKey('boss.id')) - # Configure an 'employer' relationship, where Grunt references - # Boss. This is a joined-table subclass to subclass relationship, - # which is a less typical case. - - # In 0.7, "Boss.id" is the "id" column of "boss", as would be expected. - if __version__ >= "0.7": - employer = relationship("Boss", backref="employees", - primaryjoin=Boss.id==employer_id) - - # Prior to 0.7, "Boss.id" is the "id" column of "employee". - # Long story. So we hardwire the relationship against the "id" - # column of Boss' table. - elif __version__ >= "0.6": - employer = relationship("Boss", backref="employees", - primaryjoin=Boss.__table__.c.id==employer_id) - - # In 0.5, the many-to-one loader wouldn't recognize the above as a - # simple "identity map" fetch. So to give 0.5 a chance to emit - # the same amount of SQL as 0.6, we hardwire the relationship against - # "employee.id" to work around the bug. - else: - employer = relationship("Boss", backref="employees", - primaryjoin=Employee.__table__.c.id==employer_id, - foreign_keys=employer_id) - - __mapper_args__ = {'polymorphic_identity':'grunt'} + employer = relationship("Boss", backref="employees", + primaryjoin=Boss.id == employer_id) + + __mapper_args__ = {'polymorphic_identity': 'grunt'} if os.path.exists('orm2010.db'): os.remove('orm2010.db') @@ -88,101 +62,119 @@ Base.metadata.create_all(engine) sess = Session(engine) -def runit(): - # create 1000 Boss objects. +factor = 10 + +def runit(status): + num_bosses = 100 * factor + num_grunts = num_bosses * 100 + bosses = [ Boss( name="Boss %d" % i, golf_average=Decimal(random.randint(40, 150)) ) - for i in range(1000) + for i in range(num_bosses) ] sess.add_all(bosses) + status("Added %d boss objects" % num_bosses) - - # create 10000 Grunt objects. grunts = [ Grunt( name="Grunt %d" % i, savings=Decimal(random.randint(5000000, 15000000) / 100) ) - for i in range(10000) + for i in range(num_grunts) ] + status("Added %d grunt objects" % num_grunts) - # Assign each Grunt a Boss. Look them up in the DB - # to simulate a little bit of two-way activity with the - # DB while we populate. Autoflush occurs on each query. - # In 0.7 executemany() is used for all the "boss" and "grunt" - # tables since priamry key fetching is not needed. while grunts: + # this doesn't associate grunts with bosses evenly, + # just associates lots of them with a relatively small + # handful of bosses + batch_size = 100 + batch_num = (num_grunts - len(grunts)) / batch_size boss = sess.query(Boss).\ - filter_by(name="Boss %d" % (101 - len(grunts) / 100)).\ + filter_by(name="Boss %d" % batch_num).\ first() - for grunt in grunts[0:100]: + for grunt in grunts[0:batch_size]: grunt.employer = boss - grunts = grunts[100:] + grunts = grunts[batch_size:] sess.commit() + status("Associated grunts w/ bosses and committed") - report = [] - - # load all the Grunts, print a report with their name, stats, - # and their bosses' stats. - for grunt in sess.query(Grunt): - # here, the overhead of a many-to-one fetch of - # "grunt.employer" directly from the identity map - # is less than half of that of 0.6. - report.append(( - grunt.name, - grunt.savings, - grunt.employer.name, - grunt.employer.golf_average - )) -import cProfile, os, pstats + # do some heavier reading + for i in range(5): + status("Heavy query run #%d" % (i + 1)) -filename = "orm2010.profile" -cProfile.runctx('runit()', globals(), locals(), filename) -stats = pstats.Stats(filename) + report = [] -counts_by_methname = dict((key[2], stats.stats[key][0]) for key in stats.stats) + # load all the Grunts, print a report with their name, stats, + # and their bosses' stats. + for grunt in sess.query(Grunt): + report.append(( + grunt.name, + grunt.savings, + grunt.employer.name, + grunt.employer.golf_average + )) -print("SQLA Version: %s" % __version__) -print("Total calls %d" % stats.total_calls) -print("Total cpu seconds: %.2f" % stats.total_tt) -print('Total execute calls: %d' \ - % counts_by_methname["<method 'execute' of 'sqlite3.Cursor' " - "objects>"]) -print('Total executemany calls: %d' \ - % counts_by_methname.get("<method 'executemany' of 'sqlite3.Cursor' " - "objects>", 0)) + sess.close() # close out the session -#stats.sort_stats('time', 'calls') -#stats.print_stats() -os.system("runsnake %s" % filename) +def run_with_profile(): + import cProfile + import os + import pstats + filename = "orm2010.profile" -# SQLA Version: 0.7b1 -# Total calls 4956750 -# Total execute calls: 11201 -# Total executemany calls: 101 + def status(msg): + print(msg) -# SQLA Version: 0.6.6 -# Total calls 7963214 -# Total execute calls: 22201 -# Total executemany calls: 0 + cProfile.runctx('runit(status)', globals(), locals(), filename) + stats = pstats.Stats(filename) -# SQLA Version: 0.5.8 -# Total calls 10556480 -# Total execute calls: 22201 -# Total executemany calls: 0 + counts_by_methname = dict((key[2], stats.stats[key][0]) for key in stats.stats) + print("SQLA Version: %s" % __version__) + print("Total calls %d" % stats.total_calls) + print("Total cpu seconds: %.2f" % stats.total_tt) + print('Total execute calls: %d' \ + % counts_by_methname["<method 'execute' of 'sqlite3.Cursor' " + "objects>"]) + print('Total executemany calls: %d' \ + % counts_by_methname.get("<method 'executemany' of 'sqlite3.Cursor' " + "objects>", 0)) + #stats.sort_stats('time', 'calls') + #stats.print_stats() + os.system("runsnake %s" % filename) + # SQLA Version: 0.7b1 + # Total calls 4956750 + # Total execute calls: 11201 + # Total executemany calls: 101 + # SQLA Version: 0.6.6 + # Total calls 7963214 + # Total execute calls: 22201 + # Total executemany calls: 0 + # SQLA Version: 0.5.8 + # Total calls 10556480 + # Total execute calls: 22201 + # Total executemany calls: 0 +def run_with_time(): + import time + now = time.time() + def status(msg): + print("%d - %s" % (time.time() - now, msg)) + runit(status) + print("Total time: %d" % (time.time() - now)) +run_with_time() |