$bean-save() 在 Sugarcrm 中每条记录花费的时间太长
$bean-save() is taking way too long per record in Sugarcrm
我有一个函数可以重新计算给定模块中计算字段的值。
这适用于具有少量记录的小模块。
但是,当我在联系人或帐户等更大的模块上尝试此操作时,保存每条记录最多需要三秒钟。
超过 100,000 条记录需要 83 小时来处理。
这是我的代码。
$moduleList = array("Accounts", "Quotes");
if (!defined('sugarEntry') || !sugarEntry)
die('Not A Valid Entry Point');
require_once('include/utils.php');
require_once('include/export_utils.php');
foreach( $moduleList as $module) {
print "Updating $module...\n<br>";
$cnt = 0;
$moduleBean = BeanFactory::getBean($module);
$beanList = $moduleBean->get_full_list($order_by,$where);
if( $beanList != null ) {
foreach($beanList as $b) {
// These lines prevent the modified date and user from being changed.
$b->update_date_modified = false;
$b->update_modified_by = false;
$b->tracker_visibility = false;
$b->in_workflow = true;
$b->save();
$cnt++;
}
}
print "Finished updating: $cnt records.\n<br>";
当我记录每条记录所花费的时间时,很明显 $b->save();
花费的时间太长了。
有什么方法可以加快速度吗?
首先,我建议使用您选择的工具找出保存的哪一部分需要这么长时间... profiler/debugger/custom Timers/etc.
- 是钩子吗?如果重新计算不需要,请对其进行优化或制作自定义标志以跳过它。
- 是查询吗?分析查询 (
EXPLAIN
) 以了解向数据库添加索引是否有帮助。
- 是否日志输出过多?减少它。
- 是相关bean计算的bean加载吗?优化公式或在不需要时跳过。
您可以尝试的其他事情:
- 使用查询预过滤要重新保存的 bean(例如,如果处于特定状态或在特定相关 bean 之后修改等,则可能不需要重新计算记录?)。
- 触发更新代码中的计算字段并检查 bean 的(相关)值之后是否实际更改,如果没有,则无需重新保存它,您可以跳到下一条记录。
- 如果这只是关于更新不相关的计算字段,即使存在相关的计算字段,那么您可以决定(暂时?)将
$sugar_config['disable_related_calc_fields']
设置为 true。这样 Sugar 就不必加载那些相关的 bean。
如果没有希望了:
- 并行考虑 运行 这些任务
- 使用 SQL/SugarQuery 重写您需要更新的任何内容(可能无法实现,具体取决于复杂性和含义)。
备注:
- 请注意,至少从 Sugar 7.7 开始,
get_full_list()
已被弃用,取而代之的是 SugarQuery 和 $bean->fetchFromQuery()
。但是,我建议使用查询仅检索 IDs 并使用 BeanFactory::retrieveBean($module, $id)
加载 bean,可能在计算后分别关闭它们,使用 BeanFactory::unregisterBean($bean); unset($bean);
来帮助垃圾收集器保持低内存配置文件。
我过去也确实使用过 get_full_list()
和 fetchFromQuery
,但由于使用这种方式时 bean 没有完全加载,所以出现了灾难性的副作用而不是 BeanFactory。
所有记录因此丢失了他们的电子邮件地址(!)。我不高兴。
- Sugar 8:特别是如果您有很多联系人,table
erased_fields
上的错误默认索引会在其中只有一条记录时大大降低速度。 erased_fields
默认情况下只有一个 2 列索引(虽然在重要查询中不使用),因此您必须为这 2 列添加 2 个单独的索引,并且事情将是 很多又快了。
我有一个函数可以重新计算给定模块中计算字段的值。 这适用于具有少量记录的小模块。 但是,当我在联系人或帐户等更大的模块上尝试此操作时,保存每条记录最多需要三秒钟。
超过 100,000 条记录需要 83 小时来处理。
这是我的代码。
$moduleList = array("Accounts", "Quotes");
if (!defined('sugarEntry') || !sugarEntry)
die('Not A Valid Entry Point');
require_once('include/utils.php');
require_once('include/export_utils.php');
foreach( $moduleList as $module) {
print "Updating $module...\n<br>";
$cnt = 0;
$moduleBean = BeanFactory::getBean($module);
$beanList = $moduleBean->get_full_list($order_by,$where);
if( $beanList != null ) {
foreach($beanList as $b) {
// These lines prevent the modified date and user from being changed.
$b->update_date_modified = false;
$b->update_modified_by = false;
$b->tracker_visibility = false;
$b->in_workflow = true;
$b->save();
$cnt++;
}
}
print "Finished updating: $cnt records.\n<br>";
当我记录每条记录所花费的时间时,很明显 $b->save();
花费的时间太长了。
有什么方法可以加快速度吗?
首先,我建议使用您选择的工具找出保存的哪一部分需要这么长时间... profiler/debugger/custom Timers/etc.
- 是钩子吗?如果重新计算不需要,请对其进行优化或制作自定义标志以跳过它。
- 是查询吗?分析查询 (
EXPLAIN
) 以了解向数据库添加索引是否有帮助。 - 是否日志输出过多?减少它。
- 是相关bean计算的bean加载吗?优化公式或在不需要时跳过。
您可以尝试的其他事情:
- 使用查询预过滤要重新保存的 bean(例如,如果处于特定状态或在特定相关 bean 之后修改等,则可能不需要重新计算记录?)。
- 触发更新代码中的计算字段并检查 bean 的(相关)值之后是否实际更改,如果没有,则无需重新保存它,您可以跳到下一条记录。
- 如果这只是关于更新不相关的计算字段,即使存在相关的计算字段,那么您可以决定(暂时?)将
$sugar_config['disable_related_calc_fields']
设置为 true。这样 Sugar 就不必加载那些相关的 bean。
如果没有希望了:
- 并行考虑 运行 这些任务
- 使用 SQL/SugarQuery 重写您需要更新的任何内容(可能无法实现,具体取决于复杂性和含义)。
备注:
- 请注意,至少从 Sugar 7.7 开始,
get_full_list()
已被弃用,取而代之的是 SugarQuery 和$bean->fetchFromQuery()
。但是,我建议使用查询仅检索 IDs 并使用BeanFactory::retrieveBean($module, $id)
加载 bean,可能在计算后分别关闭它们,使用BeanFactory::unregisterBean($bean); unset($bean);
来帮助垃圾收集器保持低内存配置文件。
我过去也确实使用过get_full_list()
和fetchFromQuery
,但由于使用这种方式时 bean 没有完全加载,所以出现了灾难性的副作用而不是 BeanFactory。
所有记录因此丢失了他们的电子邮件地址(!)。我不高兴。 - Sugar 8:特别是如果您有很多联系人,table
erased_fields
上的错误默认索引会在其中只有一条记录时大大降低速度。erased_fields
默认情况下只有一个 2 列索引(虽然在重要查询中不使用),因此您必须为这 2 列添加 2 个单独的索引,并且事情将是 很多又快了。