On Nov 19, 2010, at 1:41 PM, Eoghan Murray wrote:

> I guess I can't disable the mutability flag?

not if you're changing the value "inline".  If you assign a new value, then you 
don't need "mutability".

> 
> From reading up on mutability: 
> http://www.sqlalchemy.org/docs/core/types.html#sqlalchemy.types.MutableType
> I think I understand why it's required to lookup the previous value;
> so that the orm can decide whether to construct an update query for
> the instance when a flush event occurs (is that correct?).

The ORM uses attribute set events to flag changes.    It then uses the 
"previous" value, if present, to determine if a change has taken place at flush 
time, and if so issues an UPDATE.   If "previous" is not present, in most cases 
we don't need to load it, and the UPDATE is unconditional.

With a mutable structure where the user expects inline changes to take place, 
the task is more complex, since there is no "set" event.  We have no choice but 
to immediately copy the structure on load so that we can detect this change.   
An eventual solution to this would be that we instrument the mutable structure 
itself to flag change events on occurrence, but this is a very involved 
enhancement.


> Should there be a shortcut for column assignment, so that rather than
> looking up the previous value, the column is flagged as 'mutated'?

If by "column assignment" you mean direct assignment of the attribute, i.e. 
myobject.foo = {newvalue}, that is universally considered to be an event.   We 
take the previous value and store it in the object's state, if we have it.   If 
we don't have it, in most cases we don't go back to the DB to load it - the 
column receives an UPDATE unconditionally in that case.    In the case of 
mutable, its assumed that we already have it.

> If that was the case you'd get a spurious update if the old_value
> happens to be equal to the new_value, but shouldn't it be up to the
> app programmer to do this check?
> It seems to me that there's an unnecessary lookup of the old value
> when it is being replaced wholesale,

like i said, if we don't have the "old_value", in most cases we don't bother 
loading it, the UPDATE is unconditional.  If we do have the "old value" we use 
it.    We are required to load the "old value" on change if the target is a 
collection, its a scalar attribute that is part of the object's primary key 
(I'll leave it as an exercise why that is), or a many-to-one with a non-simple 
join condition or which is using "orphan" detection, otherwise its not loaded.  
 

> which I cannot stop even though
> I've marked the column as deferred.

so here is the magic word, "deferred".  mutable + deferred has never been 
considered.    Ticket #1976 is added to evaluate if we can skip the "load" when 
the col is deferred and the value wasn't loaded.  Seems to work so far but 
needs more tests and this would probably be in 0.7.

Note however that this "SELECT" is nowheres near the central inefficiency of a 
mutable type.  The central inefficiency is that we need to scan the whole 
session on every flush and compare every mutable value to its old one.   Your 
usage of "deferred" doesn't help that too much since if you are modifying the 
item in place, we still have to store it twice and compare on every flush.    
"mutable" is not a flag you'd ever see within 100 yards of any of my 
applications until we work out a way to instrument the values.



> 
> All the best,
> 
> Eoghan
> 
> On Nov 4, 1:47 pm, Michael Bayer <mike...@zzzcomputing.com> wrote:
>> is this a mutable type like PickleType?  the previous value should not be 
>> loaded otherwise (assuming at least a recent 0.5 or 0.6 version).  If so, 
>> the mutability flag should be disabled.
>> 
>> On Nov 4, 2010, at 7:05 AM, Eoghan Murray wrote:
>> 
>> 
>> 
>>> I have the following:
>> 
>>>    objs =
>>> MyTable.query.options(defer(Table.potentially_very_long_str_column)).all()
>>>    for obj in objs:
>>>         obj.potentially_very_long_str_column = ''
>> 
>>> At the moment, I'm seeing the assignment in the loop issue the `SELECT
>>> potentially_very_long_str_column`, even though that column will be
>>> overwritten.
>> 
>>> I pdb'd this down to orm/state.py::InstanceState.modified_event()
>>> where the previous value is stored in self.committed_state
>>> I'm ignorant as to what self.committed_state is used for, but maybe
>>> rather than evaluating 'previous' value, it could be further deferred
>>> until it is needed?  This is assuming that self.committed_state will
>>> only be used up until the session is flushed (at which time the
>>> previous value would be lost)..
>> 
>>> At the moment, is there any other way of writing to a column without
>>> first reading it using the orm?
>>> Haven't checked, but I assume  sql.expression.update  doesn't have
>>> this behaviour..
>> 
>>> Cheers!
>> 
>>> Eoghan
> 
> -- 
> 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.
> 

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