On Apr 3, 2013, at 1:01 AM, Roman Yakovenko <roman.yakove...@gmail.com> wrote:

> Hello.
> 
> I am just starting with SQLAlchemy and have a small problem: my "get" query 
> is compiled every time I use it.
> According to cProfile: 
> ncalls  tottime  percall  cumtime  percall filename:lineno(function)
> 10    0.000    0.000    0.002    0.000 
> /usr/local/lib/python2.7/dist-packages/SQLAlchemy-0.8.1dev-py2.7-linux-x86_64.egg/sqlalchemy/sql/expression.py:1864(compile)
> 10    0.000    0.000    0.002    0.000 
> /usr/local/lib/python2.7/dist-packages/SQLAlchemy-0.8.1dev-py2.7-linux-x86_64.egg/sqlalchemy/sql/expression.py:1908(_compiler)
> 10    0.000    0.000    0.002    0.000 
> /usr/local/lib/python2.7/dist-packages/SQLAlchemy-0.8.1dev-py2.7-linux-x86_64.egg/sqlalchemy/sql/compiler.py:231(__init__)
> 10    0.000    0.000    0.002    0.000 
> /usr/local/lib/python2.7/dist-packages/SQLAlchemy-0.8.1dev-py2.7-linux-x86_64.egg/sqlalchemy/engine/interfaces.py:764(__init__)
> 10    0.000    0.000    0.002    0.000 
> /usr/local/lib/python2.7/dist-packages/SQLAlchemy-0.8.1dev-py2.7-linux-x86_64.egg/sqlalchemy/engine/interfaces.py:805(process)
> 90/10    0.000    0.000    0.002    0.000 
> /usr/local/lib/python2.7/dist-packages/SQLAlchemy-0.8.1dev-py2.7-linux-x86_64.egg/sqlalchemy/sql/visitors.py:73(_compiler_dispatch)
> 10    0.000    0.000    0.002    0.000 
> /usr/local/lib/python2.7/dist-packages/SQLAlchemy-0.8.1dev-py2.7-linux-x86_64.egg/sqlalchemy/sql/compiler.py:1082(visit_select)
> 
> 
> In case of native API, I would use prepare "command/statement", but it looks 
> I am missing something obvious and cannot find similar functionality in the 
> package.

the Python DBAPI doesn't have an explicit concept of a "prepared statement" - 
the idea of preparing a statement involves that a statement handle is 
established on the database server, which can then be reused.   The closest the 
DBAPI has is the "executemany()" call, which gives the DBAPI itself the option 
of using a prepared statement behind the scenes; but this option is not 
appropriate for SELECT statements since executemany() doesn't support the 
return of results.

On the Python SQL construction side, SQLAlchemy deals with expression 
constructs that are converted to strings given a database dialect as well as 
compilation options.   The amount of time in Python spent for this compilation 
is relatively small and has been optimized for many years to be as fast as 
possible.  Nevertheless, in some cases we do try to squeeze more performance 
out by caching the compiled form of these queries; the ORM in particular will 
cache the compiled form of insert/update/delete statements that are used by the 
unit of work.   

Right now, the string form of SELECT queries generated by the ORM are not 
automatically cached.   It's only worthwhile to try to cache queries that are 
"fixed", such as the get() query we're referring to here as well as some of the 
queries used by lazyloading of relationships.  The overhead of this compilation 
however is fairly minimal; reddit.com uses SQLAlchemy expression constructs for 
all database queries as well, and they serve well over two billion page views a 
month without any caching of the expression string.

There's a recipe to make use of the compiled_cache in conjunction with the 
Query object right now, which is at 
http://www.sqlalchemy.org/trac/wiki/UsageRecipes/BakedQuery .



> 
> Below, you can find a complete source code, which reproduce the issue.
> 
> Thank you!
> 
> 
> import sqlalchemy 
> import sqlalchemy.ext.declarative
> 
> Base = sqlalchemy.ext.declarative.declarative_base()
> 
> class Employee(Base):
>     __tablename__ = 'employee'
>     id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
>     name = sqlalchemy.Column(sqlalchemy.String(100), nullable=False)
> 
> def run_query(session):
>     employee_by_id = session.query(Employee)
>     for i in range(10):
>         x = employee_by_id.get(i)
>         print x.name
>     session.rollback()  
> 
> if __name__ == '__main__':
>     engine = sqlalchemy.create_engine('sqlite://')
>     Base.metadata.create_all(engine)
>     Session = sqlalchemy.orm.sessionmaker(bind=engine)
>     
>     session = Session()
>     for i in range(10):
>         session.add(Employee(id=i, name='name' + str(i)))
>     session.commit()
>        
>     import cProfile
>     cProfile.run('run_query(Session())', 'get.stats') 
> 
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
> For more options, visit https://groups.google.com/groups/opt_out.
>  
>  

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to