Re: [sqlalchemy] Feature suggestion: fake ForeignKeyConstraints to simplify joins

2013-06-13 Thread Charlie Clark

Am 13.06.2013, 21:20 Uhr, schrieb Andy :


It's the original issue.  The relation (that I want the ORM to see) isn't
what's literally set in the schema by foreign keys, and the
primaryjoin/foreign_keys ORM magic for this IMO sucks.  Something like
"onetomany" and "manytoone" in the mapper config would solve the problem
nicely.


Can't you make the join condition explicit? I seem to remember doing  
something like that recently. I don't like relying on magic ever but I do  
think that SQLAlchemy does a really excellent job in most situations. In  
others, I think you can use SQL Expressions as Mike has recently indicated  
on another thread. My big point is that people using databases have to be  
prepared to find out how to get the best use of them and that often means  
writing out a query in SQL first and then writing it in SQLAlchemy.



Well, yes, I'd always recommend Postgres over MySQL but I don't see what
the choice of backend has to do with this problem, except how well
reflection works with Postgres. From a developer's perspective MySQL's
biggest problem, apart from MyASM, is that its behaviour can be
unpredictable.


The MySQL vs PostgreSQL holy war is completely irrelevant to this issue


Indeed, but you started it! ;-)

Charlie
--
Charlie Clark
Managing Director
Clark Consulting & Research
German Office
Kronenstr. 27a
Düsseldorf
D- 40217
Tel: +49-211-600-3657
Mobile: +49-178-782-6226

--
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.
For more options, visit https://groups.google.com/groups/opt_out.




Re: [sqlalchemy] Feature suggestion: fake ForeignKeyConstraints to simplify joins

2013-06-13 Thread Andy
On Thursday, June 13, 2013 1:59:16 AM UTC-7, Charlie Clark wrote:
>
> Am 13.06.2013, 00:42 Uhr, schrieb Andy >: 
>
> >> Ah, okay. I think I understand what I was missing initially. I've had 
> >> another go at this and it seems to work as required, even on MySQL. 
>  Not 
> >> sure how this all works with SQLAlchemy but I would expect it to be 
> fine 
> >> with it. 
> >> 
> >> insert into favourites (thing_id, group_id) values (2, 2) 
> >> Error Code: 1062. Duplicate entry '2' for key 'PRIMARY'0.012 
> sec 
> >> 
> >> insert into favourites (thing_id, group_id) values (1, 3) 
> >> Error Code: 1452. Cannot add or update a child row: a foreign key 
> >> constraint fails ("favourites"."favourites", CONSTRAINT "checker"   
> >> FOREIGN 
> >> 
> >> KEY ("thing_id", "group_id") REFERENCES "groups_things" ("thing_id", 
> >> "group_id"))0.007 sec 
> >> 
> > 
> > It's not, at least with automatically configured relations, hence this 
> > thread. 
>
> What do you mean with automatically configured relations? Using SQLa to   
> define the schema? I always manage the schema directly so I don't know so 
>   
> much about that. For me, the important thing is that SQLa can work with   
> the schema with the least number of contortions and I don't see any   
> required here. 
>

It's the original issue.  The relation (that I want the ORM to see) isn't 
what's literally set in the schema by foreign keys, and the 
primaryjoin/foreign_keys ORM magic for this IMO sucks.  Something like 
"onetomany" and "manytoone" in the mapper config would solve the problem 
nicely.
 

>
> >> > Also, SERIAL?  You must be using a real database engine. 
> >> 
> >> Well, er, yes. When it comes to modelling that's where you should 
> start. 
> >> And Oracle is making progress with MySQL now that InnoDB with separate 
> >> files pro table and 5.6 even seems to have some kind of vacuuming 
> >> built-in. 
> >> 
> > 
> > I dunno.  This may be the end of my (nonexistent) web developer career, 
>   
> > but 
> > I think I will never again recommend using mysql for any purpose   
> > whatsoever 
> > (except perhaps compatibility).  I've learned my lesson.  Next time I'll 
> > use PostgreSQL. 
>
> Well, yes, I'd always recommend Postgres over MySQL but I don't see what   
> the choice of backend has to do with this problem, except how well   
> reflection works with Postgres. From a developer's perspective MySQL's   
> biggest problem, apart from MyASM, is that its behaviour can be   
> unpredictable. 
>

The MySQL vs PostgreSQL holy war is completely irrelevant to this issue :) 

-- 
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.
For more options, visit https://groups.google.com/groups/opt_out.




Re: [sqlalchemy] TypeDecorator and orm refresh

2013-06-13 Thread Florian Müller

>
> HI!
>
> I implemented a TypeDecorator which allows setting the precision of a 
> datetime value. 
>
> It does something like:
>
> *import datetime*
> *
> *
> *class PrecisionDateTime(TypeDecorator):*
> *def process_bind_param(self, value, dialect):*
> *return datetime.datetime(value.year, value.month,*
> * value.hour, value.minute,*
> * 0, 0)*
>
>
> This works but the problem is, that I have to call Session.refresh() on 
> every added (and flushed) 
> object because otherwise the date-column still has the old value (with 
> second != 0 and millisecond != 0).
>
> Is there a way the refresh could be avoided?
>
>
> you'd want to switch/augment by using a @validates rule:
>
>
> http://docs.sqlalchemy.org/en/rel_0_8/orm/mapper_config.html?highlight=validates#simple-validators
>
>
Thanks for the fast answer Michael!

Your suggestion brought me onto the right track!

I solved it like this:

*def create_dt_precision_validator(precision):*
*def validate_precision_date_time(target, value, oldvalue, initiator):*
*return change_date_precision(value, precision)*
*return validate_precision_date_time*
*
*
*
*
*@event.listens_for(orm.mapper, 'mapper_configured')*
*def add_precision_dt_validators(mapper, class_):*
*for prop in mapper.iterate_properties:*
*if isinstance(prop, ColumnProperty):*
*for column in prop.columns:*
*if isinstance(column.type, PrecisionDateTime):*
*event.listen(prop, 'set',*
* create_dt_precision_validator(*
* column.type.precision),*
* retval=True)*


Somehow I like it better when I am able to define such rules at the column 
level. But the @validators
features is good to know!

Thanks a lot,
Florian

-- 
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.
For more options, visit https://groups.google.com/groups/opt_out.




Re: [sqlalchemy] TypeDecorator and orm refresh

2013-06-13 Thread Michael Bayer

On Jun 13, 2013, at 12:03 PM, Florian Müller  wrote:

> HI!
> 
> I implemented a TypeDecorator which allows setting the precision of a 
> datetime value. 
> 
> It does something like:
> 
> import datetime
> 
> class PrecisionDateTime(TypeDecorator):
> def process_bind_param(self, value, dialect):
> return datetime.datetime(value.year, value.month,
>  value.hour, value.minute,
>  0, 0)
> 
> This works but the problem is, that I have to call Session.refresh() on every 
> added (and flushed) 
> object because otherwise the date-column still has the old value (with second 
> != 0 and millisecond != 0).
> 
> Is there a way the refresh could be avoided?

you'd want to switch/augment by using a @validates rule:

http://docs.sqlalchemy.org/en/rel_0_8/orm/mapper_config.html?highlight=validates#simple-validators


-- 
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.




Re: [sqlalchemy] SA0.7.9 - poor query performance (full scan instead of index scan because of joined table inheritance)

2013-06-13 Thread Michael Bayer

On Jun 13, 2013, at 11:03 AM, Ladislav Lenart  wrote:

> Unfortunately migrating to SA 0.9 is not an option for me at the moment due to
> severe time constraints.

I was pretty sure you'd say that, though I'm really looking to verify that my 
fixes are going to hold up under real world usage.   The issues you're having 
are real issues, and they've been fixed.

> 
> Could you please help me write SA query for 0.7.9 that uses index scan and 
> also
> loads all the necessary relations? It must be possible with a proper use of
> from_statement(), contains_eager() and/or other SA features. It is just that 
> toy
> examples in the documentation don't help me much with this complex beast.

you use the SQL expression language in conjunction with .join()/outerjoin(), 
pass to query.select_from(), then use contains_eager():

j = 
Foo.__table__.outerjoin(Bar.__table__.outerjoin(BarA.__table__).outerjoin(Data.__table__))

q = s.query(Foo).\
select_from(j).\
filter(Foo.id.in_([1, 2, 3])).\
options(
contains_eager(Foo.bar),
contains_eager(Foo.bar.of_type(BarA), BarA.data)
)



-- 
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.




[sqlalchemy] TypeDecorator and orm refresh

2013-06-13 Thread Florian Müller
HI!

I implemented a TypeDecorator which allows setting the precision of a 
datetime value. 

It does something like:

*import datetime*
*
*
*class PrecisionDateTime(TypeDecorator):*
*def process_bind_param(self, value, dialect):*
*return datetime.datetime(value.year, value.month,*
* value.hour, value.minute,*
* 0, 0)*


This works but the problem is, that I have to call Session.refresh() on 
every added (and flushed) 
object because otherwise the date-column still has the old value (with 
second != 0 and millisecond != 0).

Is there a way the refresh could be avoided?

I have SQLAlchemy version 0.7.10

Regards,
Florian

-- 
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.




Re: [sqlalchemy] SA0.7.9 - poor query performance (full scan instead of index scan because of joined table inheritance)

2013-06-13 Thread Ladislav Lenart
Hello.

Just a minor correction:

The new query can return whatever it pleases as long as it *also*
returns Foo instances with properly populated relations.

The rest of the e-mail is the same.


Please help me,

Ladislav Lenart


On 13.6.2013 17:03, Ladislav Lenart wrote:
> Unfortunately migrating to SA 0.9 is not an option for me at the moment due to
> severe time constraints.
> 
> Could you please help me write SA query for 0.7.9 that uses index scan and 
> also
> loads all the necessary relations? It must be possible with a proper use of
> from_statement(), contains_eager() and/or other SA features. It is just that 
> toy
> examples in the documentation don't help me much with this complex beast.
> 
> Here is a simplified version of my problem:
> 
> Foo
> bar (can be NULL)
> 
> Bar
> 
> BarA (subclass of Bar)
> data -> Data (cannot be NULL)
> 
> Data
> value (string)
> 
> I need to rewrite this query:
> 
> q = session.query(Foo).filter(Foo.id.in_(...))
> q = q.options(
> joinedload_all(Foo.bar, BarA.data)
> )
> 
> in such a way that it does NOT perform any full scan and also populates
> Foo.bar.data.value of each returned Foo. The new query can return whatever it
> pleases as long as it returns Foo instances with properly populated relations.
> 
> Please help me write it (or tell me that it is not possible in SA 0.7.9, 
> though
> I highly doubt that).
> 
> 
> Thank you,
> 
> Ladislav Lenart
> 
> 
> On 13.6.2013 15:51, Michael Bayer wrote:
>> Please try out 0.9 from the git master which fixes the issue of the nested 
>> SELECT on the right side of a join. 
>>
>> Sent from my iPhone
>>
>> On Jun 13, 2013, at 9:18 AM, Ladislav Lenart  wrote:
>>
>>> Hello.
>>>
>>> I have a query that does a full scan of an inherited table with more than
>>> million rows even though I need only 100 of them (on postgres 9.1). This is 
>>> a
>>> real bummer! Please help me rewrite the SA query or instruct postgres to 
>>> not do
>>> this stupidity.
>>>
>>>
>>> I have the following setup (only the interesting relations):
>>>
>>>Contact
>>>contact_tags -> ContactTag (collection)
>>>phones -> Phone (collection)
>>>emails -> Email (collection)
>>>
>>>ContactTag
>>>tag -> Tag (cannot be NULL)
>>>
>>>PersonalContact (Contact subclass)
>>>partner -> Partner (can be NULL)
>>>client -> PersonalClient (can be NULL)
>>>
>>>CorporateContact (Contact subclass)
>>>client -> CorporateClient (can be NULL)
>>>
>>>Client
>>>
>>>PersonalClient (Client subclass)
>>>data -> PersonalData (cannot be NULL)
>>>
>>>CorporateClient (Client subclass)
>>>data -> CorporateData (cannot be NULL)
>>>
>>>
>>> I have the following query that loads data of one window:
>>>
>>># window (input argument) is a list of id values.
>>>q = session.query(PersonalContact).filter(PersonalContact.id.in_(window)
>>>q = q.options(
>>>subqueryload_all(PersonalContact.contact_tags, ContactTag.tag),
>>>subqueryload(PersonalContact.phones),
>>>subqueryload(PersonalContact.emails),
>>>joinedload_all(
>>>PersonalContact.partner,
>>>Partner.personal_data,
>>>PersonalData.address,
>>>   ),
>>>joinedload_all(
>>>PersonalContact.client,
>>>PersonalClient.data,
>>>PersonalData.address
>>>),
>>>)
>>>
>>>
>>> (Note that I have similar query for CorporateContact. Infact, I generate 
>>> them
>>> both in the same method.)
>>>
>>> It produces SQL like this (the problematic part is emphasized):
>>>
>>>SELECT *
>>>FROM
>>>contact
>>>JOIN personal_contact ON contact.id = personal_contact.id
>>>-- ***
>>>LEFT OUTER JOIN (
>>>SELECT *
>>>FROM
>>>client
>>>JOIN personal_client ON client.id = personal_client.id
>>>) AS anon_1 ON personal_contact.client_id = anon_1.personal_client_id
>>>-- ***
>>>LEFT OUTER JOIN partner AS partner_1
>>>ON personal_contact.partner_id = partner_1.id
>>>LEFT OUTER JOIN personal_data AS personal_data_1
>>>ON partner_1.personal_data_id = personal_data_1.id
>>>LEFT OUTER JOIN address AS address_1
>>>ON personal_data_1.address_id = address_1.id
>>>LEFT OUTER JOIN personal_data AS personal_data_2
>>>ON anon_1.personal_client_data_id = personal_data_2.id
>>>LEFT OUTER JOIN address AS address_2
>>>ON personal_data_2.address_id = address_2.id
>>>WHERE personal_contact.id IN (...)
>>>
>>>
>>> The inner select directly corresponds to joinedload of 
>>> PersonalContact.client, a
>>> PersonalClient instance (and a Client subclass).
>>>
>>> The postgres does a full scan of tables Client and PersonalClient even 
>>> though I
>>> will need at mo

Re: [sqlalchemy] SA0.7.9 - poor query performance (full scan instead of index scan because of joined table inheritance)

2013-06-13 Thread Ladislav Lenart
Unfortunately migrating to SA 0.9 is not an option for me at the moment due to
severe time constraints.

Could you please help me write SA query for 0.7.9 that uses index scan and also
loads all the necessary relations? It must be possible with a proper use of
from_statement(), contains_eager() and/or other SA features. It is just that toy
examples in the documentation don't help me much with this complex beast.

Here is a simplified version of my problem:

Foo
bar (can be NULL)

Bar

BarA (subclass of Bar)
data -> Data (cannot be NULL)

Data
value (string)

I need to rewrite this query:

q = session.query(Foo).filter(Foo.id.in_(...))
q = q.options(
joinedload_all(Foo.bar, BarA.data)
)

in such a way that it does NOT perform any full scan and also populates
Foo.bar.data.value of each returned Foo. The new query can return whatever it
pleases as long as it returns Foo instances with properly populated relations.

Please help me write it (or tell me that it is not possible in SA 0.7.9, though
I highly doubt that).


Thank you,

Ladislav Lenart


On 13.6.2013 15:51, Michael Bayer wrote:
> Please try out 0.9 from the git master which fixes the issue of the nested 
> SELECT on the right side of a join. 
> 
> Sent from my iPhone
> 
> On Jun 13, 2013, at 9:18 AM, Ladislav Lenart  wrote:
> 
>> Hello.
>>
>> I have a query that does a full scan of an inherited table with more than
>> million rows even though I need only 100 of them (on postgres 9.1). This is a
>> real bummer! Please help me rewrite the SA query or instruct postgres to not 
>> do
>> this stupidity.
>>
>>
>> I have the following setup (only the interesting relations):
>>
>>Contact
>>contact_tags -> ContactTag (collection)
>>phones -> Phone (collection)
>>emails -> Email (collection)
>>
>>ContactTag
>>tag -> Tag (cannot be NULL)
>>
>>PersonalContact (Contact subclass)
>>partner -> Partner (can be NULL)
>>client -> PersonalClient (can be NULL)
>>
>>CorporateContact (Contact subclass)
>>client -> CorporateClient (can be NULL)
>>
>>Client
>>
>>PersonalClient (Client subclass)
>>data -> PersonalData (cannot be NULL)
>>
>>CorporateClient (Client subclass)
>>data -> CorporateData (cannot be NULL)
>>
>>
>> I have the following query that loads data of one window:
>>
>># window (input argument) is a list of id values.
>>q = session.query(PersonalContact).filter(PersonalContact.id.in_(window)
>>q = q.options(
>>subqueryload_all(PersonalContact.contact_tags, ContactTag.tag),
>>subqueryload(PersonalContact.phones),
>>subqueryload(PersonalContact.emails),
>>joinedload_all(
>>PersonalContact.partner,
>>Partner.personal_data,
>>PersonalData.address,
>>   ),
>>joinedload_all(
>>PersonalContact.client,
>>PersonalClient.data,
>>PersonalData.address
>>),
>>)
>>
>>
>> (Note that I have similar query for CorporateContact. Infact, I generate them
>> both in the same method.)
>>
>> It produces SQL like this (the problematic part is emphasized):
>>
>>SELECT *
>>FROM
>>contact
>>JOIN personal_contact ON contact.id = personal_contact.id
>>-- ***
>>LEFT OUTER JOIN (
>>SELECT *
>>FROM
>>client
>>JOIN personal_client ON client.id = personal_client.id
>>) AS anon_1 ON personal_contact.client_id = anon_1.personal_client_id
>>-- ***
>>LEFT OUTER JOIN partner AS partner_1
>>ON personal_contact.partner_id = partner_1.id
>>LEFT OUTER JOIN personal_data AS personal_data_1
>>ON partner_1.personal_data_id = personal_data_1.id
>>LEFT OUTER JOIN address AS address_1
>>ON personal_data_1.address_id = address_1.id
>>LEFT OUTER JOIN personal_data AS personal_data_2
>>ON anon_1.personal_client_data_id = personal_data_2.id
>>LEFT OUTER JOIN address AS address_2
>>ON personal_data_2.address_id = address_2.id
>>WHERE personal_contact.id IN (...)
>>
>>
>> The inner select directly corresponds to joinedload of 
>> PersonalContact.client, a
>> PersonalClient instance (and a Client subclass).
>>
>> The postgres does a full scan of tables Client and PersonalClient even 
>> though I
>> will need at most 100 rows from each one.
>>
>> However, if I rewrite the problematic part by hand like this:
>>
>>LEFT OUTER JOIN client
>>ON personal_contact.client_id = client.id
>> LEFT OUTER JOIN personal_client
>>ON client.id = personal_client.id
>>
>> it works like a charm.
>>
>> Unfortunately I don't know how to write such a query in SA. I am really 
>> stuck so
>> any help is much appreciated.
>>
>>
>> Thank you,
>>
>> Ladislav Lenart
>>
>>
>> 

Re: [sqlalchemy] Re: SqlAlchemy use in Twisted threads

2013-06-13 Thread Richard Gerd Kuesters
I'm glad you got a better solution. The key is now test it and see if 
memory leaks and connections get closed properly.


The main problem in Twisted, IMHO, is the usage of "maybeDeferred" in 
some points, which can go to a thread or stay in the main thread, which 
is a little hard to predict and then lead to memory leaks. Another 
problem (that I get sometimes) is applications running on single-core 
servers. Things get mixed up :)


If your application is all structured in thread calls, then the Pylons 
approach is almost the same, and it might work as expected. But, if you 
plan to use anything else from Twisted (conch, names, or 3rd parties, 
like Cyclone or txAmqp), first check if their calls are all deferreds to 
other threads :) Cyclone, for instance, doesn't create a thread for 
every request it receives; it's up to you to do thatน.



Cheers,
Richard.

น I may be wrong about this, but at the time I used it, I had to defer 
all incoming requests to threads to get sessions closed properly.


On 06/13/2013 10:30 AM, writes_on wrote:

Hi all,

Based on some comments here and in the SqlAlchemy IRC chat room, I've 
updated my decorator to make some changes. Here is the updated version:


class ScopedSession(object):
SESSIONMAKER = None  # this is the single sessionmaker instance
def __init__(self, engine, auto_commit=True):
assert engine is not None, "Must pass a valid engine parameter"
self._auto_commit = auto_commit
if ScopedSession.SESSIONMAKER is None:
ScopedSession.SESSIONMAKER = 
scoped_session(sessionmaker(expire_on_commit=True, bind=engine))

def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
db_session = ScopedSession.SESSIONMAKER()
try:
results = func(db_session, *args, **kwargs)
db_session.commit()
# should we rollback for safety?
if not self._auto_commit:
db_session.rollback()
except:
db_session.rollback()
raise
finally:
# release the session back to the connection pool
db_session.close()
return results
return wrapper


This version changes the code to a class based decorator so that I can 
create and use a single sessionmaker. It also calls the close() method 
of the session at the end of the decorator to release the session back 
to the connection pool.


In response to using SqlAlchemy in a thread (in Twisted), I also write 
Pylons applications which use SqlAlchemy as the database backend. 
Since every request is a thread in Pylons, SqlAlchemy runs in those 
threads without a problem, so I'm not sure I see the problem running 
it in Twisted. The threads.deferToThread(...) call is nothing fancy in 
Twisted, it gets a thread from a thread pool, runs the passed function 
in that thread, and returns a deferred that fires in the main Twisted 
thread when the thread ends. This code looks like this:


@defer.inlineCallbacks
def update(data):
# this function does some db work
@ScopedSession(engine=engine)
def process(session):
# this method will be run in a thread and is passed a session 
by the decorator

results = session.query()
return results
# call the internal process function in a thread
try:
results = yield threads.deferToThread(process)
 except Exception, e:
# do something with exceptions
defer.returnValue(results)

Using @defer.inlineCallbacks makes calling asynchronous code easier to 
write in Twisted than using the traditional callback model (in my 
opinion). Defining the process() method internally gives it access to 
the parameters within the scope it's defined within and allows me to 
simplify it's parameters down to the session received from the 
@ScopedSession decorator. process() returns the SqlAlchemy results 
normally and is received into results when the yield returns from the 
thread (deferred fires). In the above example the session is commited 
and closed by the @ScopedSession decorator because I didn't override 
the default auto_commite=True parameter.


Any comments, criticisms or suggestions are welcome, and again, thanks 
in advance!

Doug



--
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 th

Re: [sqlalchemy] SA0.7.9 - poor query performance (full scan instead of index scan because of joined table inheritance)

2013-06-13 Thread Michael Bayer
Please try out 0.9 from the git master which fixes the issue of the nested 
SELECT on the right side of a join. 

Sent from my iPhone

On Jun 13, 2013, at 9:18 AM, Ladislav Lenart  wrote:

> Hello.
> 
> I have a query that does a full scan of an inherited table with more than
> million rows even though I need only 100 of them (on postgres 9.1). This is a
> real bummer! Please help me rewrite the SA query or instruct postgres to not 
> do
> this stupidity.
> 
> 
> I have the following setup (only the interesting relations):
> 
>Contact
>contact_tags -> ContactTag (collection)
>phones -> Phone (collection)
>emails -> Email (collection)
> 
>ContactTag
>tag -> Tag (cannot be NULL)
> 
>PersonalContact (Contact subclass)
>partner -> Partner (can be NULL)
>client -> PersonalClient (can be NULL)
> 
>CorporateContact (Contact subclass)
>client -> CorporateClient (can be NULL)
> 
>Client
> 
>PersonalClient (Client subclass)
>data -> PersonalData (cannot be NULL)
> 
>CorporateClient (Client subclass)
>data -> CorporateData (cannot be NULL)
> 
> 
> I have the following query that loads data of one window:
> 
># window (input argument) is a list of id values.
>q = session.query(PersonalContact).filter(PersonalContact.id.in_(window)
>q = q.options(
>subqueryload_all(PersonalContact.contact_tags, ContactTag.tag),
>subqueryload(PersonalContact.phones),
>subqueryload(PersonalContact.emails),
>joinedload_all(
>PersonalContact.partner,
>Partner.personal_data,
>PersonalData.address,
>   ),
>joinedload_all(
>PersonalContact.client,
>PersonalClient.data,
>PersonalData.address
>),
>)
> 
> 
> (Note that I have similar query for CorporateContact. Infact, I generate them
> both in the same method.)
> 
> It produces SQL like this (the problematic part is emphasized):
> 
>SELECT *
>FROM
>contact
>JOIN personal_contact ON contact.id = personal_contact.id
>-- ***
>LEFT OUTER JOIN (
>SELECT *
>FROM
>client
>JOIN personal_client ON client.id = personal_client.id
>) AS anon_1 ON personal_contact.client_id = anon_1.personal_client_id
>-- ***
>LEFT OUTER JOIN partner AS partner_1
>ON personal_contact.partner_id = partner_1.id
>LEFT OUTER JOIN personal_data AS personal_data_1
>ON partner_1.personal_data_id = personal_data_1.id
>LEFT OUTER JOIN address AS address_1
>ON personal_data_1.address_id = address_1.id
>LEFT OUTER JOIN personal_data AS personal_data_2
>ON anon_1.personal_client_data_id = personal_data_2.id
>LEFT OUTER JOIN address AS address_2
>ON personal_data_2.address_id = address_2.id
>WHERE personal_contact.id IN (...)
> 
> 
> The inner select directly corresponds to joinedload of 
> PersonalContact.client, a
> PersonalClient instance (and a Client subclass).
> 
> The postgres does a full scan of tables Client and PersonalClient even though 
> I
> will need at most 100 rows from each one.
> 
> However, if I rewrite the problematic part by hand like this:
> 
>LEFT OUTER JOIN client
>ON personal_contact.client_id = client.id
> LEFT OUTER JOIN personal_client
>ON client.id = personal_client.id
> 
> it works like a charm.
> 
> Unfortunately I don't know how to write such a query in SA. I am really stuck 
> so
> any help is much appreciated.
> 
> 
> Thank you,
> 
> Ladislav Lenart
> 
> 
> -- 
> 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.




[sqlalchemy] Re: SqlAlchemy use in Twisted threads

2013-06-13 Thread writes_on
Hi all,

Based on some comments here and in the SqlAlchemy IRC chat room, I've 
updated my decorator to make some changes. Here is the updated version:

class ScopedSession(object):
SESSIONMAKER = None  # this is the single sessionmaker instance

def __init__(self, engine, auto_commit=True):
assert engine is not None, "Must pass a valid engine parameter"
self._auto_commit = auto_commit
if ScopedSession.SESSIONMAKER is None:
ScopedSession.SESSIONMAKER = 
scoped_session(sessionmaker(expire_on_commit=True, bind=engine))

def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
db_session = ScopedSession.SESSIONMAKER()
try:
results = func(db_session, *args, **kwargs)
db_session.commit()
# should we rollback for safety?
if not self._auto_commit:
db_session.rollback()
except:
db_session.rollback()
raise
finally:
# release the session back to the connection pool
db_session.close()
return results
return wrapper


This version changes the code to a class based decorator so that I can 
create and use a single sessionmaker. It also calls the close() method of 
the session at the end of the decorator to release the session back to the 
connection pool. 

In response to using SqlAlchemy in a thread (in Twisted), I also write 
Pylons applications which use SqlAlchemy as the database backend. Since 
every request is a thread in Pylons, SqlAlchemy runs in those threads 
without a problem, so I'm not sure I see the problem running it in Twisted. 
The threads.deferToThread(...) call is nothing fancy in Twisted, it gets a 
thread from a thread pool, runs the passed function in that thread, and 
returns a deferred that fires in the main Twisted thread when the thread 
ends. This code looks like this:

@defer.inlineCallbacks
def update(data):
# this function does some db work
@ScopedSession(engine=engine)
def process(session):
# this method will be run in a thread and is passed a session by 
the decorator
results = session.query()
return results
# call the internal process function in a thread
try:
results = yield threads.deferToThread(process)
 except Exception, e:
# do something with exceptions
defer.returnValue(results)

Using @defer.inlineCallbacks makes calling asynchronous code easier to 
write in Twisted than using the traditional callback model (in my opinion). 
Defining the process() method internally gives it access to the parameters 
within the scope it's defined within and allows me to simplify it's 
parameters down to the session received from the @ScopedSession decorator. 
process() returns the SqlAlchemy results normally and is received into 
results when the yield returns from the thread (deferred fires). In the 
above example the session is commited and closed by the @ScopedSession 
decorator because I didn't override the default auto_commite=True parameter.

Any comments, criticisms or suggestions are welcome, and again, thanks in 
advance!
Doug



-- 
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.




[sqlalchemy] SA0.7.9 - poor query performance (full scan instead of index scan because of joined table inheritance)

2013-06-13 Thread Ladislav Lenart
Hello.

I have a query that does a full scan of an inherited table with more than
million rows even though I need only 100 of them (on postgres 9.1). This is a
real bummer! Please help me rewrite the SA query or instruct postgres to not do
this stupidity.


I have the following setup (only the interesting relations):

Contact
contact_tags -> ContactTag (collection)
phones -> Phone (collection)
emails -> Email (collection)

ContactTag
tag -> Tag (cannot be NULL)

PersonalContact (Contact subclass)
partner -> Partner (can be NULL)
client -> PersonalClient (can be NULL)

CorporateContact (Contact subclass)
client -> CorporateClient (can be NULL)

Client

PersonalClient (Client subclass)
data -> PersonalData (cannot be NULL)

CorporateClient (Client subclass)
data -> CorporateData (cannot be NULL)


I have the following query that loads data of one window:

# window (input argument) is a list of id values.
q = session.query(PersonalContact).filter(PersonalContact.id.in_(window)
q = q.options(
subqueryload_all(PersonalContact.contact_tags, ContactTag.tag),
subqueryload(PersonalContact.phones),
subqueryload(PersonalContact.emails),
joinedload_all(
PersonalContact.partner,
Partner.personal_data,
PersonalData.address,
   ),
joinedload_all(
PersonalContact.client,
PersonalClient.data,
PersonalData.address
),
)


(Note that I have similar query for CorporateContact. Infact, I generate them
both in the same method.)

It produces SQL like this (the problematic part is emphasized):

SELECT *
FROM
contact
JOIN personal_contact ON contact.id = personal_contact.id
-- ***
LEFT OUTER JOIN (
SELECT *
FROM
client
JOIN personal_client ON client.id = personal_client.id
) AS anon_1 ON personal_contact.client_id = anon_1.personal_client_id
-- ***
LEFT OUTER JOIN partner AS partner_1
ON personal_contact.partner_id = partner_1.id
LEFT OUTER JOIN personal_data AS personal_data_1
ON partner_1.personal_data_id = personal_data_1.id
LEFT OUTER JOIN address AS address_1
ON personal_data_1.address_id = address_1.id
LEFT OUTER JOIN personal_data AS personal_data_2
ON anon_1.personal_client_data_id = personal_data_2.id
LEFT OUTER JOIN address AS address_2
ON personal_data_2.address_id = address_2.id
WHERE personal_contact.id IN (...)


The inner select directly corresponds to joinedload of PersonalContact.client, a
PersonalClient instance (and a Client subclass).

The postgres does a full scan of tables Client and PersonalClient even though I
will need at most 100 rows from each one.

However, if I rewrite the problematic part by hand like this:

LEFT OUTER JOIN client
ON personal_contact.client_id = client.id
 LEFT OUTER JOIN personal_client
ON client.id = personal_client.id

it works like a charm.

Unfortunately I don't know how to write such a query in SA. I am really stuck so
any help is much appreciated.


Thank you,

Ladislav Lenart


-- 
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.




Re: [sqlalchemy] Related object not updating on flush, only on commit

2013-06-13 Thread Robert Buchholz
Hey Michael,

thanks for your fast response and especially the recipe. I completely
forgot the FAQ. Most of my questions are usually covered by the
documentation, and search engines seem to prefer StackOverflow et al.

On Mi, 2013-06-12 at 16:15 -0400, Michael Bayer wrote:
> This is the FAQ entry we've had in place for many years:
> 
> http://www.sqlalchemy.org/trac/wiki/FAQ#Isetthefoo_idattributeonmyinstanceto7butthefooattributeisstillNone-shouldntithaveloadedFoowithid7
> 
> But also, I've added a new recipe which shows how to get this behavior, and 
> also makes apparent some of the difficulties in establishing it completely 
> (requires a many-to-one be in place, accessing collections on the "reverse" 
> side can be tricky):
> 
> http://www.sqlalchemy.org/trac/wiki/UsageRecipes/ExpireRelationshipOnFKChange
> 

The FAQ and recipe state that recommended use is to set the relationship
property instead of settings its underlying column -- and this what I
usually do. When I ran into this, I used the 'onupdate' column parameter
with a python function to set a 'last modified by' attribute. Doing an
'onupdate' on the relation does not seem to be easily accessible through
a parameter, although I'm certain it's possible hooking into the right
event.

For now, I'll go with a scoped version of your recipe. Thanks a lot!


Robert

-- 
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.




Re: [sqlalchemy] Feature suggestion: fake ForeignKeyConstraints to simplify joins

2013-06-13 Thread Charlie Clark

Am 13.06.2013, 00:42 Uhr, schrieb Andy :


Ah, okay. I think I understand what I was missing initially. I've had
another go at this and it seems to work as required, even on MySQL.  Not
sure how this all works with SQLAlchemy but I would expect it to be fine
with it.

insert into favourites (thing_id, group_id) values (2, 2)
Error Code: 1062. Duplicate entry '2' for key 'PRIMARY'0.012 sec

insert into favourites (thing_id, group_id) values (1, 3)
Error Code: 1452. Cannot add or update a child row: a foreign key
constraint fails ("favourites"."favourites", CONSTRAINT "checker"  
FOREIGN


KEY ("thing_id", "group_id") REFERENCES "groups_things" ("thing_id",
"group_id"))0.007 sec



It's not, at least with automatically configured relations, hence this
thread.


What do you mean with automatically configured relations? Using SQLa to  
define the schema? I always manage the schema directly so I don't know so  
much about that. For me, the important thing is that SQLa can work with  
the schema with the least number of contortions and I don't see any  
required here.



> Also, SERIAL?  You must be using a real database engine.

Well, er, yes. When it comes to modelling that's where you should start.
And Oracle is making progress with MySQL now that InnoDB with separate
files pro table and 5.6 even seems to have some kind of vacuuming
built-in.



I dunno.  This may be the end of my (nonexistent) web developer career,  
but
I think I will never again recommend using mysql for any purpose  
whatsoever

(except perhaps compatibility).  I've learned my lesson.  Next time I'll
use PostgreSQL.


Well, yes, I'd always recommend Postgres over MySQL but I don't see what  
the choice of backend has to do with this problem, except how well  
reflection works with Postgres. From a developer's perspective MySQL's  
biggest problem, apart from MyASM, is that its behaviour can be  
unpredictable.


Charlie
--
Charlie Clark
Managing Director
Clark Consulting & Research
German Office
Kronenstr. 27a
Düsseldorf
D- 40217
Tel: +49-211-600-3657
Mobile: +49-178-782-6226

--
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.