On Dec 22, 2009, at 5:20 PM, Igor Katson wrote:

>> 0.5 supports this using the "postgres_returning" argument to update() and 
>> insert(), but the ORM doesn't make use of it.  in 0.6, the feature has been 
>> generalized using the returning() method on insert() and update(), and the 
>> ORM will use it to fetch new primary key identifiers.
>> 
>> It does not take effect within the ORM for inline SQL other than primary key 
>> identifiers, but you can use an insert() with returning() manually to 
>> achieve that effect.
>> 
> Why not, Michael? Is it hard to implement this? This seems to be pretty 
> useful and performance-improving, reducing the amount of selects needed 
> when coding unaware of object expiry.

because a. I dont have the time to implement conditional returning() awareness 
within the ORM and b. I don't think it will have as dramatic a performance 
impact as you expect.   When I added default returning() support for insert() 
statements by default, the number of function call counts in our performance 
tests went up, due to the additional complexity.  I have made the 
automatic-returning feature optional for all dialects since its not really 
clear that performance is actually enhanced.   So its a race between Python 
method performance, which is abysmal, and overhead of SQL round trips.    
Future enhancements like turning ResultProxy into C (which some work has been 
done on) could then be game changers again.

Other reasons performance might not increase much at all are:

1. a typical ORM application may create/modify a bunch of objects, then call 
commit().  By default everything is expired unconditionally in that case - 
RETURNING for non-primary key columns is wasted overhead.
2. the "set an attribute to a SQL expression" use case is very rare.  in most 
cases the additional complexity of deciding about returning() at the ORM level 
just adds complexity for no reason.
3. The use case of SQL-level defaults/onupdates on columns is there, but again 
the usual use here is for timestamps and such that usually aren't fetched in 
the same transaction as the one in which they are flushed - fetching them back 
just so they can be thrown away is again wasted overhead.
4. its not clear overall if returning() is faster for all DBAPIs - in 
particular the mechanics of using RETURNING with oracle and MSSQL are pretty 
complex.


> 
> P.S. And in SQLAlchemy 0.5, what's the most orm-like way to do solve 
> this? In my code, it looks like this now, cause I didn't find an easier 
> (less lines + less sql-like code) way to do it.
>        columns = ','.join([str(col) for col in obj_table.c])
>        query = '''UPDATE %(table)s
>        SET col = col + %(value)s
>        WHERE id = %(id)s
>        RETURNING %(columns)s''' % {
>            'id': id,
>            'columns': columns,
>            'table': obj_table,
>            'value': value
>        }
>        obj = meta.Session.query(Obj).from_statement(query).first()

As far as the rendering above, you should use the postgres_returning keyword in 
conjunction with an update() construct, instead of piecing together a string.  
It should be in the API documentation.    The usage of query(Obj) to call it 
and get an object back from RETURNING is novel and I hadn't thought of that.    
 You need to ensure that the rows you're matching are not already present in 
the session, or have been expired, else the new state will not be reflected in 
the objects.

You also should take a measurement of performance enhancement with the above 
technique, vs. using query.update() or Session.execute(update()) and then 
re-selecting the rows back, or just allowing the natural expiration to result 
in individual SELECTs as needed.   

If you truly have some very performance critical section where thousands of 
rows are being inserted/updated, the ORM is going to give you fairly mediocre 
performance with or without RETURNING, as it is designed to do lots of the 
thinking and effort for you in a very generic (read: unoptimized) way and hence 
is an expensive route to go no matter what.  You'd be better off dropping into 
the usage of insert()/update()/delete() constructs and not attempting to 
reinstate the new rows back into ORM objects, since that is all an expensive 
process designed to make the production of source code easier.   In this case 
your source code is being made more difficult to produce anyway so the ORM 
might not be worth it.


--

You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalch...@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