summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2020-05-25 22:36:44 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2020-05-28 14:38:56 -0400
commit77f1b7d236dba6b1c859bb428ef32d118ec372e6 (patch)
tree7fae8eaaf303d6ce02bd423abf216550001e2f7b /examples
parent366e88ea0e5c5417184c1dd4776cff752560631d (diff)
downloadsqlalchemy-77f1b7d236dba6b1c859bb428ef32d118ec372e6.tar.gz
callcount reductions and refinement for cached queries
This commit includes that we've removed the "_orm_query" attribute from compile state as well as query context. The attribute created reference cycles and also added method call overhead. As part of this change, the interface for ORMExecuteState changes a bit, as well as the interface for the horizontal sharding extension which now deprecates the "query_chooser" callable in favor of "execute_chooser", which receives the contextual object. This will also work more nicely when we implement the new execution path for bulk updates and deletes. Pre-merge execution options for statement, connection, arguments all up front in Connection. that way they can be passed to the before_execute / after_execute events, and the ExecutionContext doesn't have to merge as second time. Core execute is pretty close to 1.3 now. baked wasn't using the new one()/first()/one_or_none() methods, fixed that. Convert non-buffered cursor strategy to be a stateless singleton. inline all the paths by which the strategy gets chosen, oracle and SQL Server dialects make use of the already-invoked post_exec() hook to establish the alternate strategies, and this is actually much nicer than it was before. Add caching to mapper instance processor for getters. Identified a reference cycle per query that was showing up as a lot of gc cleanup, fixed that. After all that, performance not budging much. Even test_baked_query now runs with significantly fewer function calls than 1.3, still 40% slower. Basically something about the new patterns just makes this slower and while I've walked a whole bunch of them back, it hardly makes a dent. that said, the performance issues are relatively small, in the 20-40% time increase range, and the new caching feature does provide for regular ORM and Core queries that are cached, and they are faster than non-cached. Change-Id: I7b0b0d8ca550c05f79e82f75cd8eff0bbfade053
Diffstat (limited to 'examples')
-rw-r--r--examples/performance/__init__.py21
-rw-r--r--examples/performance/short_selects.py17
2 files changed, 26 insertions, 12 deletions
diff --git a/examples/performance/__init__.py b/examples/performance/__init__.py
index f4f53f0d5..b6c74d7fe 100644
--- a/examples/performance/__init__.py
+++ b/examples/performance/__init__.py
@@ -19,7 +19,7 @@ individual suites to be run::
$ python -m examples.performance --help
usage: python -m examples.performance [-h] [--test TEST] [--dburl DBURL]
[--num NUM] [--profile] [--dump]
- [--runsnake] [--echo]
+ [--echo]
{bulk_inserts,large_resultsets,single_inserts}
@@ -35,7 +35,6 @@ individual suites to be run::
default is module-specific
--profile run profiling and dump call counts
--dump dump full call profile (implies --profile)
- --runsnake invoke runsnakerun (implies --profile)
--echo Echo SQL output
An example run looks like::
@@ -208,6 +207,7 @@ We can run our new script directly::
""" # noqa
import argparse
import cProfile
+import gc
import os
import pstats
import re
@@ -233,6 +233,7 @@ class Profiler(object):
self.num = options.num
self.echo = options.echo
self.sort = options.sort
+ self.gc = options.gc
self.stats = []
@classmethod
@@ -305,10 +306,15 @@ class Profiler(object):
def _run_test(self, fn):
if self._setup:
self._setup(self.dburl, self.echo, self.num)
+ if self.gc:
+ # gc.set_debug(gc.DEBUG_COLLECTABLE)
+ gc.set_debug(gc.DEBUG_STATS)
if self.profile or self.dump:
self._run_with_profile(fn, self.sort)
else:
self._run_with_time(fn)
+ if self.gc:
+ gc.set_debug(0)
@classmethod
def main(cls):
@@ -369,6 +375,9 @@ class Profiler(object):
help="print callers as well (implies --dump)",
)
parser.add_argument(
+ "--gc", action="store_true", help="turn on GC debug stats"
+ )
+ parser.add_argument(
"--echo", action="store_true", help="Echo SQL output"
)
args = parser.parse_args()
@@ -432,11 +441,3 @@ class TestResult(object):
def _dump_raw(self):
self.stats.dump_stats(self.profile.raw)
-
- def _runsnake(self):
- filename = "%s.profile" % self.test.__name__
- try:
- self.stats.dump_stats(filename)
- os.system("runsnake %s" % filename)
- finally:
- os.remove(filename)
diff --git a/examples/performance/short_selects.py b/examples/performance/short_selects.py
index 38bc1508a..2f2b19c17 100644
--- a/examples/performance/short_selects.py
+++ b/examples/performance/short_selects.py
@@ -69,6 +69,9 @@ def test_orm_query(n):
"""test a straight ORM query of the full entity."""
session = Session(bind=engine)
for id_ in random.sample(ids, n):
+ # new style
+ # stmt = future_select(Customer).where(Customer.id == id_)
+ # session.execute(stmt).scalars().unique().one()
session.query(Customer).filter(Customer.id == id_).one()
@@ -77,6 +80,11 @@ def test_orm_query_cols_only(n):
"""test an ORM query of only the entity columns."""
session = Session(bind=engine)
for id_ in random.sample(ids, n):
+ # new style
+ # stmt = future_select(
+ # Customer.id, Customer.name, Customer.description
+ # ).filter(Customer.id == id_)
+ # session.execute(stmt).scalars().unique().one()
session.query(Customer.id, Customer.name, Customer.description).filter(
Customer.id == id_
).one()
@@ -90,7 +98,9 @@ def test_cached_orm_query(n):
"""test new style cached queries of the full entity."""
s = Session(bind=engine)
for id_ in random.sample(ids, n):
- stmt = s.query(Customer).filter(Customer.id == id_)
+ # this runs significantly faster
+ stmt = future_select(Customer).where(Customer.id == id_)
+ # stmt = s.query(Customer).filter(Customer.id == id_)
s.execute(stmt, execution_options={"compiled_cache": cache}).one()
@@ -99,9 +109,12 @@ def test_cached_orm_query_cols_only(n):
"""test new style cached queries of the full entity."""
s = Session(bind=engine)
for id_ in random.sample(ids, n):
- stmt = s.query(
+ stmt = future_select(
Customer.id, Customer.name, Customer.description
).filter(Customer.id == id_)
+ # stmt = s.query(
+ # Customer.id, Customer.name, Customer.description
+ # ).filter(Customer.id == id_)
s.execute(stmt, execution_options={"compiled_cache": cache}).one()