-
-
Notifications
You must be signed in to change notification settings - Fork 452
Description
In Magento, any time you use a setter, the property _hasDataChanges is set to true, even when you're not actually changing anything.
I.e. this code will set _hasDataChanges to true, even though we're not changing anything.
$stockItem->setQty($stockItem->getQty());
This is disturbing me, because it slows down Magento, causing unneeded save and MySQL stuff to run.
I wanted to open this issue as a way to discuss this.
On occasion, I have in fact overridden the setData() method for specific models so _hasDataChanges remains false. In my experience it can greatly improve stock qty import scripts. It's mind blowing how much speed can be gained.
My implementation looks like this:
public function setData($key, $value = null) {
// In our version, we first check if we are actually changing something. Not setting the _hasDataChanges flag regardless.
if (!is_array($key) && !is_object($value)) {
$oldValue = $this->_data[$key] ?? null;
if ($oldValue === $value) {
// No need to change anything
return $this;
} elseif ($oldValue === (string) $value) {
// Still no need to change anything
return $this;
} elseif (is_numeric($value) && is_numeric($oldValue) && '' . round($oldValue, 8) === '' . round($value, 8)) {
// The number is the same, with up to 8 decimals accuracy
return $this;
}
}
return parent::setData($key, $value);
}
and
public function setOrigData($key = null, $data = null) {
if (is_null($key)) {
$this->_origData = $this->_data;
// Added this line because we need to reset the previous "true" value.
$this->_hasDataChanges = false;
} else {
$this->_origData[$key] = $data;
}
return $this;
}
Why not make this standard for all models? Yes, it is a bit tricky, but isn't it worth it given the huge speed gain that is possible?
One part of the "tricky" side is that events are also triggered. IMHO I'd say "fuck it". The speed gain is very important and you're not actually saving anything, so why should an event be triggered?
And yes, I am breaking backwards compatibility here.
Preconditions (*)
- Any installation since the dawn of Magento
Steps to reproduce (*)
- Use any setter on any DB-backed model and set to the same value already there.
- Run save() on the model. It will save, even though there is no need for it.
Expected result (*)
- Don't save at all, because there is no need, greatly improving speed!
Actual result (*)
- It saves the existing data back to the DB like we're used to, also triggering events...