Great thanx for the answer,

I have tried your suggestion with AliasedClass and it works fine for
me, but unfortunately on my production machines I have version 0.4.4
of SA and AliasedClass is in 0.5.x .

I think I will rebuild my model into single inheritance.

On Jan 21, 8:38 pm, Michael Bayer <mike...@zzzcomputing.com> wrote:
> If I make a slight change to the particular line of code which  
> generates this subquery:
>
> Index: lib/sqlalchemy/orm/strategies.py
> ===================================================================
> --- lib/sqlalchemy/orm/strategies.py    (revision 5711)
> +++ lib/sqlalchemy/orm/strategies.py    (working copy)
> @@ -673,7 +673,7 @@
>           towrap = context.eager_joins.setdefault(entity_key,  
> default_towrap)
>
>           # create AliasedClauses object to build up the eager query.
> -        clauses =  
> mapperutil.ORMAdapter(mapperutil.AliasedClass(self.mapper),
> +        clauses =  
> mapperutil.ORMAdapter(mapperutil.AliasedClass(self.mapper,  
> self.mapper._with_polymorphic_selectable),
>                       equivalents=self.mapper._equivalent_columns)
>
> running a simple test case of Company->eagerload->Engineer(subclass of  
> Person) leads to this query:
>
> SELECT companies.company_id AS companies_company_id, companies.name AS  
> companies_name, people.person_id AS people_person_id,  
> engineers.person_id AS engineers_person_id, people.company_id AS  
> people_company_id, people.name AS people_name, people.type AS  
> people_type, engineers.status AS engineers_status,  
> engineers.engineer_name AS engineers_engineer_name,  
> engineers.primary_language AS engineers_primary_language
> FROM companies LEFT OUTER JOIN (people JOIN engineers ON  
> people.person_id = engineers.person_id) ON companies.company_id =  
> people.company_id
>
> which in fact fails to execute on SQLite.    Additionally, the  
> "people" and "engineers" tables are not aliased, meaning if your query  
> happened to already be joined to "people" or "engineers", the  
> eagerload would ruin the query.    The query above might work on PG or  
> MySQL, but still breaks the general contract expected by the automatic  
> eagerloading feature.   Many tests would fail.
>
> This is just one example of a whole universe of reasons why wrapping  
> any mapped "selectable" within a single named unit allows a tremendous  
> amount of capability with regards to generation of queries without  
> direct user involvement, with a reasonable level of code complexity  
> and a great degree of stability.   Similar logic exists if you said  
> query(Company).outerjoin(Company.employees) - the "employees"  
> collection, being mapped to a join, would be wrapped in a subquery.    
> If I comment out the logic which does that, lots of tests fail  
> particularly within the inheritance tests, including when run on MySQL  
> or Postgres, which supports the nested JOIN syntax, yet the particular  
> quirks of the query being tested fail to return the expected results  
> when the encapsulation of sub-selectables is removed.
>
> This is not to say that conditional logic to adequately detect when we  
> can "skip" the subquery without impacting results couldn't be  
> added.    From poking around the code a bit, it seems like it could be  
> doable - although the logic would have to take place only for certain  
> dialects, in certain circumstances, and particularly with regards to  
> the aliasing of an eager loaded selectable it still may be very  
> difficult to deal with that.    There are also issues which would need  
> to be solved on the SQLA side regarding detection of join conditions  
> to a Join object as opposed to an alias() of that join - again  
> probably solvable but not working at the moment.
>
> While I'm shaking my head saying its not worth it, I would welcome  
> your input into the current codebase if you'd like to help work up  
> test cases and such for this capability - I'm always open to potential  
> improvements.
>
> But when you consider that upon embarking upon that very significant  
> and code-destablizing task, the only reason it even needs to be  
> considered, versus remaining with the current very clean, stable, well  
> tested, and relational approach, is because *MySQL alone can't  
> properly optimize subqueries*, it begins to seem like a waste of  
> time.    There are other free and open databases that perform better  
> than MySQL and don't have these issues (namely Postgres).   There are  
> ways which SQLA allows you to write your own query for performance-
> critical sections if needed such as the one which you mentioned.    
> you can also do it this way (again, would fail on SQLite):
>
> a = aliased(Engineer, people.join(engineers))
> s.query(Company).outerjoin((a,  
> Company.employees)).options(contains_eager(Company.employees,  
> alias=a)).all()
>
> the above approach can also be distilled into a single function to cut  
> down on redundancy:
>
> q = eagerload_engineers(q)
>
> But for MySQL in particular, I would advise not using joined table  
> inheritance at all, in favor of single table inheritance.   The last  
> project I did was with MySQL and we just used single inheritance, and  
> it runs great - I made lots of improvements to the single inheritance  
> system to support it.   MySQL just has too many issues with joins and  
> subqueries in general such that a more normalized approach is not  
> really worth it.   While increased complexity to SQLA might allow SQLA  
> to better work around MySQL's specific issues, it starts to feel like  
> SQLA, a project that earns about $500 a year in donations, is taking  
> responsibility for an issue that MySQL, a product that has received  
> $1B from Sun, should really be addressing itself.
>
> On Jan 21, 2009, at 1:25 PM, Tomasz Domanski wrote:
>
>
>
> > Hello all,
>
> > I have a question about SQLAlchemy when dealing with joining on one-
> > to-
> > many relationships.
> > When I try to load data with eager=True for relation with objects,
> > which subclasses from some base class, SQLAlchemy generates query with
> > subselect.
>
> > Subselects are quite painful for me, as I'm using MySQL so I can't
> > count on query-optymalization.
>
> > Is there some easy way to tell mapper to use outerjoins instead of
> > subselects?
>
> > Here is some simple example, that generates such a query:
>
> > let say we have 3 classes:  Employee(object), Doctor(Employee),
> > MedCompany(object)
>
> > e_mapper = mapper( Employee,
> >    employees,
> >    polymorphic_on=employees.c.type,
> >    polymorphic_identity='employee' )
>
> > d_mapper = mapper( Doctor,
> >    doctors,
> >    inherits = Employee,
> >    polymorphic_identity='doctor' )
>
> > c_mapper = mapper( Company,
> >    companies,
> >    properties={
> >        'employees' : relation(Doctor, lazy=False)
> >    }
> > )
>
> > data = session.query(Company).all()
>
> > it generates something like:
>
> > SELECT companies... , anon_1...
> > FROM companies
> > LEFT OUTER JOIN (
> >    SELECT employees... , doctors...
> >    FROM employees INNER JOIN doctors ON employees.employee_id =
> > doctors.doctor_id
> > ) AS anon_1 ON companies.company_id = anon_1.employees_company_id
>
> > One solution could be:
>
> > remove : "lazy=False" from c_mapper
>
> > and write query like:
>
> > data = session.query(Company).outerjoin(employees
> >             ).outerjoin(doctors
> >             ).options(
> >                   contains_eager('employees')
> >             ).all()
>
> > But is there any way to avoid writing such ugly queries?
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to