Skip to content

Commit

Permalink
Merge "Deannotate ORM columns in ColumnEntity"
Browse files Browse the repository at this point in the history
  • Loading branch information
zzzeek authored and Gerrit Code Review committed Nov 3, 2018
2 parents 664290a + 88bfa1b commit 4811e35
Show file tree
Hide file tree
Showing 4 changed files with 237 additions and 8 deletions.
9 changes: 9 additions & 0 deletions doc/build/changelog/unreleased_12/4347.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.. change::
:tags: bug, orm
:tickets: 4347

Fixed a minor performance issue which could in some cases add unnecessary
overhead to result fetching, involving the use of ORM columns and entities
that include those same columns at the same time within a query. The issue
has to do with hash / eq overhead when referring to the column in different
ways.
11 changes: 11 additions & 0 deletions lib/sqlalchemy/orm/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -4243,6 +4243,11 @@ def row_processor(self, query, context, result):
else:
column = query._adapt_clause(self.column, False, True)

if column._annotations:
# annotated columns perform more slowly in compiler and
# result due to the __eq__() method, so use deannotated
column = column._deannotate()

if context.adapter:
column = context.adapter.columns[column]

Expand All @@ -4251,6 +4256,12 @@ def row_processor(self, query, context, result):

def setup_context(self, query, context):
column = query._adapt_clause(self.column, False, True)

if column._annotations:
# annotated columns perform more slowly in compiler and
# result due to the __eq__() method, so use deannotated
column = column._deannotate()

context.froms += tuple(self.froms)
context.primary_columns.append(column)

Expand Down
149 changes: 148 additions & 1 deletion test/aaa_profiling/test_orm.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.orm import mapper, relationship, \
sessionmaker, Session, defer, joinedload, defaultload, selectinload, \
Load, configure_mappers
Load, configure_mappers, Bundle
from sqlalchemy import testing
from sqlalchemy.testing import profiling
from sqlalchemy.testing import fixtures
from sqlalchemy.testing.schema import Table, Column
from sqlalchemy import inspect


class MergeTest(fixtures.MappedTest):

@classmethod
Expand Down Expand Up @@ -954,3 +955,149 @@ def go():
q.options(*opts)
go()


class AnnotatedOverheadTest(fixtures.MappedTest):
@classmethod
def define_tables(cls, metadata):
Table(
'a',
metadata,
Column('id', Integer, primary_key=True),
Column('data', String(50))
)

@classmethod
def setup_classes(cls):
class A(cls.Basic):
pass

@classmethod
def setup_mappers(cls):
A = cls.classes.A
a = cls.tables.a

mapper(A, a)

@classmethod
def insert_data(cls):
A = cls.classes.A
s = Session()
s.add_all([A(data='asdf') for i in range(5)])
s.commit()

def test_no_bundle(self):
A = self.classes.A
s = Session()

q = s.query(A).select_from(A)

@profiling.function_call_count()
def go():
for i in range(100):
q.all()
go()

def test_no_entity_wo_annotations(self):
A = self.classes.A
a = self.tables.a
s = Session()

q = s.query(a.c.data).select_from(A)

@profiling.function_call_count()
def go():
for i in range(100):
q.all()
go()

def test_no_entity_w_annotations(self):
A = self.classes.A
s = Session()
q = s.query(A.data).select_from(A)

@profiling.function_call_count()
def go():
for i in range(100):
q.all()
go()

def test_entity_w_annotations(self):
A = self.classes.A
s = Session()
q = s.query(
A, A.data
).select_from(A)

@profiling.function_call_count()
def go():
for i in range(100):
q.all()
go()

def test_entity_wo_annotations(self):
A = self.classes.A
a = self.tables.a
s = Session()
q = s.query(
A, a.c.data
).select_from(A)

@profiling.function_call_count()
def go():
for i in range(100):
q.all()
go()

def test_no_bundle_wo_annotations(self):
A = self.classes.A
a = self.tables.a
s = Session()
q = s.query(
a.c.data, A
).select_from(A)

@profiling.function_call_count()
def go():
for i in range(100):
q.all()
go()

def test_no_bundle_w_annotations(self):
A = self.classes.A
s = Session()
q = s.query(
A.data, A
).select_from(A)

@profiling.function_call_count()
def go():
for i in range(100):
q.all()
go()

def test_bundle_wo_annotation(self):
A = self.classes.A
a = self.tables.a
s = Session()
q = s.query(
Bundle("ASdf", a.c.data), A
).select_from(A)

@profiling.function_call_count()
def go():
for i in range(100):
q.all()
go()

def test_bundle_w_annotation(self):
A = self.classes.A
s = Session()
q = s.query(
Bundle("ASdf", A.data), A
).select_from(A)

@profiling.function_call_count()
def go():
for i in range(100):
q.all()
go()
76 changes: 69 additions & 7 deletions test/profiles.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# /home/classic/dev/sqlalchemy/test/profiles.txt
# This file is written out on a per-environment basis.
# For each test in aaa_profiling, the corresponding function and
# For each test in aaa_profiling, the corresponding function and
# environment is located within this file. If it doesn't exist,
# the test is skipped.
# If a callcount does exist, it is compared to what we received.
# If a callcount does exist, it is compared to what we received.
# assertions are raised if the counts do not match.
#
# To add a new callcount test, apply the function_call_count
# decorator and re-run the tests using the --write-profiles
#
# To add a new callcount test, apply the function_call_count
# decorator and re-run the tests using the --write-profiles
# option - this file will be rewritten including the new count.
#
#

# TEST: test.aaa_profiling.test_compiler.CompileTest.test_insert

Expand Down Expand Up @@ -196,6 +196,69 @@ test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_postgre
test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_sqlite_pysqlite_dbapiunicode_cextensions 158
test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 158

# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation

test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_sqlite_pysqlite_dbapiunicode_cextensions 48456,48400
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 51456,51400
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.7_sqlite_pysqlite_dbapiunicode_cextensions 50867,50800
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 54067,54000

# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation

test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_sqlite_pysqlite_dbapiunicode_cextensions 48480,48480
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 51480,51480
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.7_sqlite_pysqlite_dbapiunicode_cextensions 50880,50880
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 54080,54080

# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations

test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 46205,46200
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 49205,49200
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 48008,48000
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 51208,51200

# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations

test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 46280,46280
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 49280,49280
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 48080,48080
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 51280,51280

# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle

test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle 2.7_sqlite_pysqlite_dbapiunicode_cextensions 38500,38500
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 41000,41000
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle 3.7_sqlite_pysqlite_dbapiunicode_cextensions 41200,41200
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 43900,43900

# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations

test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 46205,46200
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 49205,49200
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 48008,48000
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 51208,51200

# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations

test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 46280,46280
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 49280,49280
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 48080,48080
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 51280,51280

# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations

test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 25437,25437
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 26937,26937
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 27535,27535
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 29235,29235

# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations

test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 25517,25517
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 27017,27017
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 27615,27615
test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 29315,29315

# TEST: test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set

test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_mssql_pyodbc_dbapiunicode_cextensions 4256
Expand Down Expand Up @@ -475,7 +538,6 @@ test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_postgresql_
test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_sqlite_pysqlite_dbapiunicode_cextensions 455708
test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 455708


# TEST: test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results

test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_mssql_pyodbc_dbapiunicode_cextensions 466544
Expand Down

0 comments on commit 4811e35

Please sign in to comment.