granite icon indicating copy to clipboard operation
granite copied to clipboard

`update` should only update changed fields on record

Open kalinon opened this issue 2 years ago • 4 comments

Currently Granite will perform an UPDATE and provide all fields for the update statement. It should only perform an update on the fields that changed for optimization.

kalinon avatar Apr 25 '23 12:04 kalinon

Doing this means we need something akin to the dirty module provided by ActiveRecord.

It's a good idea, I'm all for it.

In AR it's not always clear if this is automatically enabled or not. I think this should come standard enabled so no one has to think hard about it.

Link to the module so anyone else can check and get an idea of what's going on. https://api.rubyonrails.org/classes/ActiveModel/Dirty.html#method-i-changed-3F

This means we need to add:

  1. In memory tracking of the original object values and their types
  2. Update/override the setter methods so that it can track when an attribute value has changed, and which attribute it is, prior to assigning the new value

My first thought is that we should probably do this with a hash that takes all values in as String for key and value, but can convert them back to the column type when doing any comparison of the old and new value. I could be wrong on this, but, from my understanding it's Union types that increase compile time and potentially are a performance hit, so having a single type and just converting on the fly would be more performant.

That part is probably worth testing to confirm.

crimson-knight avatar Apr 25 '23 12:04 crimson-knight

We could possibly use the hashdiff lib i wrote: https://github.com/spoved/hashdiff.cr

tho, it would require keeping a "pristine" record and "dirty" record to compare. which i dont know if i like. probably some sort of dirty flag and a record of which field was changed would be a better path.

kalinon avatar Apr 25 '23 12:04 kalinon

@kalinon I'd rather not introduce outside libraries into Granite if at all possible, and I think this is simple enough that including it in Granite itself should be easy to do.

crimson-knight avatar Apr 25 '23 13:04 crimson-knight

It seems like MySQL doesn't care about this: https://stackoverflow.com/questions/3186908/mysql-update-statement-overhead-for-same-values

postgres might benefit from this: https://dba.stackexchange.com/questions/118178/does-updating-a-row-with-the-same-value-actually-update-the-row#:~:text=PostgreSQL%20is%20a%20database%20and,the%20new%20value%20or%20not.

Can't tell how SQLite would perform from some quick googling.

a-alhusaini avatar May 21 '23 22:05 a-alhusaini