On 10/22/2016 05:55 AM, Anton Baranenko wrote:
Hi all,

I'd like to ask for your help with implementing the following.

I have quite a complex query with subqueries generated in the
application. In general the structure would look like this:

draft_data = aliased(
Draft.query.filter(
Draft.author_user_id == drafts_from_user_id  # draft_from_user_id is a bind 
parameter
    ).subquery(),
    name='draft_data'
)


then a bunch of similar subqueries that get integrated into the main
query like this:

query = query.outerjoin(draft_data, WorkItemData.draft_id == draft_data.c.id)


The actual query has around six parametrized subqueries like this.

The resulting query is pretty fast, but it's compilation takes about 50%
to 100% time of its execution => I decided to go with the BakedQuery.

However from the BakedQuery documentation I could not figure out how I
should use it with joins / subqueries. Should I BakedQuery subqueries
separately and then somehow join them with the main BakedQuery (how?).
Should I somehow do the BakedQuery only of the main query (what to do
with subqueries then?).

The thing about BakedQuery is that it is caching the fully formed SQL string. There is no way to use it only part of the way, when you want your query to get the performance enhancement of "baked", the final, outermost query has to be BakedQuery, which means every function that generates a portion of the query inside of it must produce the identical SQL in all cases, otherwise you can't cache that end product.

In the case of a subquery, subquery() actually produces a core Select / Alias object so you're no longer a Query, but it does that by doing the same compile_context() which is part of the computation time you're looking to save. So you'd probably want the production of that subquery to also be inside of a callable function that won't get called if the BakedQuery is pulling from the cache, although if it's not, it's not that critical either.

The main thing is always that every function you pass to BakedQuery must produce a Query object that will result in the identical SQL every time. So the parameters are the biggest part of it, that is, any kind of dynamic value needs to be outside of the callables, and bindparam() used internally.

An example would be:

def do_a_thing(session, thing, otherthing):
    query = bakery(lambda s: s.query(SomeClass))

    # approach #1: don't "bake" the subquery part.  use parameters
    # always though
subq = session.query(OtherClass.id).filter(OtherClass.thing == bindparam('thing')).subquery()

    query += lambda q: q.join(subq, subq.c.id == SomeClass.other_id)

    # approach #2: "bake" the subquery too.
    def other_subq(q):
subq = q.session.query(ThirdClass.id).filter(ThirdClass.otherthing == bindparam('otherthing')).subquery()
        q = q.join(subq, subq.c.id == SomeClass.thirdthing_id)
        return q

     query += other_subq

     return query(session).params(thing=thing, otherthing=otherthing)

It is definitely a little more weird and tedious to do a "builder" approach with BakedQuery because you have to be mindful of the "every function must produce the identical SQL each time" requirement. For more examples you can see in the unit tests some more complex constructions like in https://bitbucket.org/zzzeek/sqlalchemy/src/1f32d014da5d40406cd5d3996be5283c2fc57b26/test/ext/test_baked.py?at=master&fileviewer=file-view-default#test_baked.py-466 , and the synopsis at http://docs.sqlalchemy.org/en/latest/orm/extensions/baked.html#synopsis shows a little bit how things look as well.









Thank you for any help,
Anton

--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and
Verifiable Example. See http://stackoverflow.com/help/mcve for a full
description.
---
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
<mailto:sqlalchemy+unsubscr...@googlegroups.com>.
To post to this group, send email to sqlalchemy@googlegroups.com
<mailto:sqlalchemy@googlegroups.com>.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

--
SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 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 https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to