I am writing a script to add values to a custom attribute for 10 thousand customers. I have two questions here.
-
when we update custom attribute values for product, we can use:
$resource = $product->getResource(); $product->setData($attribute, $value); $resource->saveAttribute($product,$attribute);
which is very fast. But as for customer, it does not have getResource() method. The only way I know is: $this->_customerRepository->save($customer); which is very very slow. so how can I update the customers values faster?
-
when I update these values in bulk, I wrote the script as followings, it was running fine at the first hundreds of customers data updating, but then throws exception:
(/chroot/home/.../html/vendor/magento/framework/Exception/FileSystemException.php): failed to open stream: Too many open files in /chroot/home/.../html/vendor/composer/ClassLoader.php on line 444
I Googled this problem and someone says it is relevant to the settings of sever. However, since we rent the server and have no authorization to change it, how should I modify my code and make it use less resources?
protected function updateAttributes($customersListData,$output) { $time_start = microtime(true); $totalLength = sizeof($customersListData); foreach ($customersListData as $customerIndex => $singleCustomerData) { try { $id = $singleCustomerData['id']; $customer = $this->_customerRepository->getById($id); $arrayKeys = array_keys($singleCustomerData); array_shift($arrayKeys); foreach ($arrayKeys as $singleKey) { if (empty($singleCustomerData[$singleKey])) { $singleCustomerData[$singleKey] = ""; } $time_now = microtime(true); $time_used = $time_now - $time_start; $finished_records = (int)$customerIndex + 1; $output->writeln("Updating attribute: ".$singleCustomerData[$singleKey].". " .$finished_records ."/".$totalLength." done. will finsih in: ". round($time_used / $finished_records * ($totalLength - $finished_records), 0). "s."); $customer->setData($singleKey, $singleCustomerData[$singleKey]); } $this->_customerRepository->save($customer); unset($customer); } catch (Exception $e) { $output->writeln($e->getMessage()); continue; } } }
2
Answers
in this case you have 2 Database requests per iteration in the foreach. this is like 20’000 requests within a minute or somewhat.
Here an idea in pseudo-code:
Use bellow class in constructors
Alternative Faster Option
You should use php programmatically out side magento and make database connection with that. Fetch data and update magento attributes. this will be faster and easy to update attributes.