英文:
WordPress + ACF + programmatically adding a large amount of data
问题
The code you provided seems to be dealing with updating ACF repeater fields in WordPress based on data in the $data
array. To improve performance and avoid timeouts, you can consider the following optimizations:
-
Bulk Operations: Instead of updating fields row by row, you can use ACF's
update_field
function to update the entire repeater field at once. This reduces the number of database queries. -
Database Direct Insert: If performance is a critical concern and the data structure allows it, you can consider inserting data directly into the MySQL database using SQL queries. However, this approach requires careful handling of data to maintain data integrity.
-
Batch Processing: To avoid script timeouts, you can split the update process into smaller batches. Process a limited number of companies at a time, and then continue with the next batch.
-
Increase Maximum Execution Time: If you have control over the server settings, you can increase the maximum execution time in PHP to allow longer script execution. However, this is not recommended for production environments.
Here's an example of how you can use the update_field
function to update the repeater field in bulk:
// Create an array to store the repeater field data
$values = array();
foreach ($data['candles']['data'] as $row) {
$values[] = array(
'open' => $row[0],
'close' => $row[1],
'high' => $row[2],
'low' => $row[3],
'value' => $row[4],
'volume' => $row[5],
'begin' => $row[6],
'end' => $row[7]
);
}
// Update or add the repeater field data in bulk
update_field('com_array_data', $values, $company_id);
Remember to consider the potential data integrity issues when using direct database inserts, and make sure to create backups or test thoroughly before implementing such changes in a production environment.
英文:
I have WordPress + company post type + ACF repeater field for each company + data array in $data
. The code below checks the number of rows in the repeater field and compares them with the number of rows in the array. If there are fewer or more rows in the repeater than there are rows in the array, then we add or remove them. And then we update all these fields by adding data from $data to them.
This code works correctly for me, with one exception - there is a lot of data and it simply does not have time to do it for all companies (the update occurs once a day). Makes 5-6 first companies from the list and goes into timeout. I'm thinking of getting around this by adding data directly to mysql, but I can't solve it in any way. My current code is below:
// Getting the current number of fields in the ACF repeater
$com_array_data = get_field('com_array_data', $company_id);
if (is_array($com_array_data) || $com_array_data instanceof Countable) {
$count = count($com_array_data);
} else {
$count = 0;
}
// Getting the number of data rows in array
$data_count = count($data['candles']['data']);
// If the number of rows in the repeater is less than the number of rows in array, add the missing ones to the repeater
if ($count < $data_count) {
for ($i = $count; $i < $data_count; $i++) {
add_row('com_array_data', array(
'open' => '',
'close' => '',
'high' => '',
'low' => '',
'value' => '',
'volume' => '',
'begin' => '',
'end' => ''
), $company_id);
}
}
// If the number of rows of fields in the repeater is greater than the number of rows in array, we delete the extra ones in the repeater
if ($count > $data_count) {
for ($i = $count; $i > $data_count; $i--) {
delete_row('com_array_data', $i, $company_id);
}
}
// Updating the field values in the ACF repeater
if (have_rows($com_array_data)) {
while (have_rows($com_array_data)) {
the_row();
$row_index = get_row_index();
update_sub_field('open', $data['candles']['data'][$row_index - 1][0], $company_id);
update_sub_field('close', $data['candles']['data'][$row_index - 1][1], $company_id);
update_sub_field('high', $data['candles']['data'][$row_index - 1][2], $company_id);
update_sub_field('low', $data['candles']['data'][$row_index - 1][3], $company_id);
update_sub_field('value', $data['candles']['data'][$row_index - 1][4], $company_id);
update_sub_field('volume', $data['candles']['data'][$row_index - 1][5], $company_id);
update_sub_field('begin', $data['candles']['data'][$row_index - 1][6], $company_id);
update_sub_field('end', $data['candles']['data'][$row_index - 1][7], $company_id);
}
}
I managed to improve it a little by changing the part in adding data and it seems now there is no timeout, but it's still not the best option and it doesn't work very fast, I think it can still be improved.
$values = array();
foreach ($data['candles']['data'] as $row) {
$values[] = array(
'open' => $row[0],
'close' => $row[1],
'high' => $row[2],
'low' => $row[3],
'value' => $row[4],
'volume' => $row[5],
'begin' => $row[6],
'end' => $row[7]
);
}
if ($count > 0) {
update_field('com_array_data', $values, $company_id);
} else {
add_row('com_array_data', $values, $company_id);
}
I would be grateful for a review of the code and options for improving it, primarily to improve performance.
upd: And yet the second option also goes into timeout. «PHP Fatal error: Maximum execution time of 320 seconds exceeded ... wp-includes/class-wpdb.php»
答案1
得分: 1
最佳优化方法是并行运行多个进程。将公司分成组,然后同时运行每个组的代码。
您的代码看起来很干净,但我看到一个潜在的改进是限制下标操作的次数。而不是这样:
update_sub_field('open', $data['candles']['data'][$row_index - 1][0], $company_id);
...
可以这样:
$row_data = $data['candles']['data'];
...
update_sub_field('open', $row_data[$row_index - 1][0], $company_id);
...
在最近版本的PHP中有很多自动优化,所以这可能不会有太大的差别,但也值得一试。
顺便说一下,您是否在运行最新版本的PHP?如果不是,升级可能会使一切运行速度更快。
如果一切都失败了,您可以增加服务器的超时时间...
英文:
The best optimization you could do is to run several processes in parallel.
Divide the companies into groups and then run the code for each group concurrently.
Your code looks pretty clean, but one potential improvement I see is to limit the number of subscripting operations. Instead of this:
update_sub_field('open', $data['candles']['data'][$row_index - 1][0], $company_id);
...
do this:
$row_data = $data['candles']['data'];
...
update_sub_field('open', $row_data[$row_index - 1][0], $company_id);
...
There are alot of automatic optimizations in the recent versions of PHP, so this might not make any difference, but worth a shot.
Speaking of which, are you running the latest version of PHP? If not, upgrading might make everything run a bit faster.
If all else fails, you could increase the timeout on the server...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论