$bean-save() is taking way too long per record in Sugarcrm
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I am having a function that recalculates the value of calculated fields in given modules.
This works fine for small modules with small number of records.
However When I try this on bigger modules like Contacts or Accounts, saving each record take up to three seconds.
With more than 100,000 records this takes 83 Hours to process.
This is my code.
$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>";
When I log the time each record takes it is then clear that $b->save();
is what takes too long.
Is there any way to speed this up ?
php sugarcrm
add a comment |
I am having a function that recalculates the value of calculated fields in given modules.
This works fine for small modules with small number of records.
However When I try this on bigger modules like Contacts or Accounts, saving each record take up to three seconds.
With more than 100,000 records this takes 83 Hours to process.
This is my code.
$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>";
When I log the time each record takes it is then clear that $b->save();
is what takes too long.
Is there any way to speed this up ?
php sugarcrm
add a comment |
I am having a function that recalculates the value of calculated fields in given modules.
This works fine for small modules with small number of records.
However When I try this on bigger modules like Contacts or Accounts, saving each record take up to three seconds.
With more than 100,000 records this takes 83 Hours to process.
This is my code.
$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>";
When I log the time each record takes it is then clear that $b->save();
is what takes too long.
Is there any way to speed this up ?
php sugarcrm
I am having a function that recalculates the value of calculated fields in given modules.
This works fine for small modules with small number of records.
However When I try this on bigger modules like Contacts or Accounts, saving each record take up to three seconds.
With more than 100,000 records this takes 83 Hours to process.
This is my code.
$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>";
When I log the time each record takes it is then clear that $b->save();
is what takes too long.
Is there any way to speed this up ?
php sugarcrm
php sugarcrm
asked Nov 16 '18 at 19:37
HamzaouiiiHamzaouiii
1587
1587
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
First of all I'd recommend finding out what part of the save takes so long, using the tool of your choice... profiler/debugger/custom Timers/etc.
- Is it a hook? Optimize it or make a custom flag to skip it if not needed for the recalc.
- Is it a query? Analyse the queries (
EXPLAIN
) to find out if adding indices to your database could help. - Is it excessive log output? Reduce it.
- Is it the bean loading for related bean calculation? Optimize formulas or skip if not needed.
Other things you could try:
- Prefilter which beans you want to resave using a Query (e.g. maybe record recalc not necessary if in certain state or modified after a certain related bean etc?).
- Trigger updating calculated fields in your code and check if (relevant) values of the bean where actually changed after, if not then there's no need to resave it and you can skip to the next record instead.
- If this is just about updating non-related calculated fields even although related calculated fields exist, then you could decide to (temporarily?) set
$sugar_config['disable_related_calc_fields']
to true. That way Sugar wouldn't have to load those related beans.
If there is no hope left:
- Consider running those tasks in parallel
- Rewrite whatever you need to update using SQL/SugarQuery (may not be possible, depending on complexity and implications).
Notes:
- Be aware that
get_full_list()
is deprecated since at least Sugar 7.7 and replaced by SugarQuery and$bean->fetchFromQuery()
. However I'd recommend using a Query to only retrieve the IDs and useBeanFactory::retrieveBean($module, $id)
to load the beans, possibly dismissing them each after computation, usingBeanFactory::unregisterBean($bean); unset($bean);
to help the garbage collector with keeping a low memory profile.
Also I did useget_full_list()
andfetchFromQuery
in the past with catastrophic side-effects due to beans not getting fully loaded when using that way instead of BeanFactory.
All records lost their email-addresses(!) as a result. I was not pleased. - Sugar 8: Especially if you have a lot of contacts, bad default indices on the table
erased_fields
will slow things down a lot as soon as it has a single record in it.erased_fields
only has a 2-column index by default (which isn't used in important queries though), so you'll have to add 2 individual indices for those 2 columns and things will be a lot faster again.
Hi @Jay Thank you for your help! Could you please maybe tell me how is it possible to run these tasks in parallel ?
– Hamzaouiii
Nov 18 '18 at 12:06
@Hamzaouiii Well, that's outside the scope of Sugar and its Schedulers and should be only used as last resort (also it's not cloud-capable as it requires execution on the system level). You'd have to create a PHP script that loads in the sugar environment (similar to gist.github.com/bickart/5468138 ) before doing recalculations for a single module or chunk e.g. given by a call argument. Then configure the apache user's cron to run the script for each of the required modules (or even one for each chunk of records if you want to have more than one job running at a time, per module).
– Jay
Nov 18 '18 at 12:18
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53344305%2fbean-save-is-taking-way-too-long-per-record-in-sugarcrm%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
First of all I'd recommend finding out what part of the save takes so long, using the tool of your choice... profiler/debugger/custom Timers/etc.
- Is it a hook? Optimize it or make a custom flag to skip it if not needed for the recalc.
- Is it a query? Analyse the queries (
EXPLAIN
) to find out if adding indices to your database could help. - Is it excessive log output? Reduce it.
- Is it the bean loading for related bean calculation? Optimize formulas or skip if not needed.
Other things you could try:
- Prefilter which beans you want to resave using a Query (e.g. maybe record recalc not necessary if in certain state or modified after a certain related bean etc?).
- Trigger updating calculated fields in your code and check if (relevant) values of the bean where actually changed after, if not then there's no need to resave it and you can skip to the next record instead.
- If this is just about updating non-related calculated fields even although related calculated fields exist, then you could decide to (temporarily?) set
$sugar_config['disable_related_calc_fields']
to true. That way Sugar wouldn't have to load those related beans.
If there is no hope left:
- Consider running those tasks in parallel
- Rewrite whatever you need to update using SQL/SugarQuery (may not be possible, depending on complexity and implications).
Notes:
- Be aware that
get_full_list()
is deprecated since at least Sugar 7.7 and replaced by SugarQuery and$bean->fetchFromQuery()
. However I'd recommend using a Query to only retrieve the IDs and useBeanFactory::retrieveBean($module, $id)
to load the beans, possibly dismissing them each after computation, usingBeanFactory::unregisterBean($bean); unset($bean);
to help the garbage collector with keeping a low memory profile.
Also I did useget_full_list()
andfetchFromQuery
in the past with catastrophic side-effects due to beans not getting fully loaded when using that way instead of BeanFactory.
All records lost their email-addresses(!) as a result. I was not pleased. - Sugar 8: Especially if you have a lot of contacts, bad default indices on the table
erased_fields
will slow things down a lot as soon as it has a single record in it.erased_fields
only has a 2-column index by default (which isn't used in important queries though), so you'll have to add 2 individual indices for those 2 columns and things will be a lot faster again.
Hi @Jay Thank you for your help! Could you please maybe tell me how is it possible to run these tasks in parallel ?
– Hamzaouiii
Nov 18 '18 at 12:06
@Hamzaouiii Well, that's outside the scope of Sugar and its Schedulers and should be only used as last resort (also it's not cloud-capable as it requires execution on the system level). You'd have to create a PHP script that loads in the sugar environment (similar to gist.github.com/bickart/5468138 ) before doing recalculations for a single module or chunk e.g. given by a call argument. Then configure the apache user's cron to run the script for each of the required modules (or even one for each chunk of records if you want to have more than one job running at a time, per module).
– Jay
Nov 18 '18 at 12:18
add a comment |
First of all I'd recommend finding out what part of the save takes so long, using the tool of your choice... profiler/debugger/custom Timers/etc.
- Is it a hook? Optimize it or make a custom flag to skip it if not needed for the recalc.
- Is it a query? Analyse the queries (
EXPLAIN
) to find out if adding indices to your database could help. - Is it excessive log output? Reduce it.
- Is it the bean loading for related bean calculation? Optimize formulas or skip if not needed.
Other things you could try:
- Prefilter which beans you want to resave using a Query (e.g. maybe record recalc not necessary if in certain state or modified after a certain related bean etc?).
- Trigger updating calculated fields in your code and check if (relevant) values of the bean where actually changed after, if not then there's no need to resave it and you can skip to the next record instead.
- If this is just about updating non-related calculated fields even although related calculated fields exist, then you could decide to (temporarily?) set
$sugar_config['disable_related_calc_fields']
to true. That way Sugar wouldn't have to load those related beans.
If there is no hope left:
- Consider running those tasks in parallel
- Rewrite whatever you need to update using SQL/SugarQuery (may not be possible, depending on complexity and implications).
Notes:
- Be aware that
get_full_list()
is deprecated since at least Sugar 7.7 and replaced by SugarQuery and$bean->fetchFromQuery()
. However I'd recommend using a Query to only retrieve the IDs and useBeanFactory::retrieveBean($module, $id)
to load the beans, possibly dismissing them each after computation, usingBeanFactory::unregisterBean($bean); unset($bean);
to help the garbage collector with keeping a low memory profile.
Also I did useget_full_list()
andfetchFromQuery
in the past with catastrophic side-effects due to beans not getting fully loaded when using that way instead of BeanFactory.
All records lost their email-addresses(!) as a result. I was not pleased. - Sugar 8: Especially if you have a lot of contacts, bad default indices on the table
erased_fields
will slow things down a lot as soon as it has a single record in it.erased_fields
only has a 2-column index by default (which isn't used in important queries though), so you'll have to add 2 individual indices for those 2 columns and things will be a lot faster again.
Hi @Jay Thank you for your help! Could you please maybe tell me how is it possible to run these tasks in parallel ?
– Hamzaouiii
Nov 18 '18 at 12:06
@Hamzaouiii Well, that's outside the scope of Sugar and its Schedulers and should be only used as last resort (also it's not cloud-capable as it requires execution on the system level). You'd have to create a PHP script that loads in the sugar environment (similar to gist.github.com/bickart/5468138 ) before doing recalculations for a single module or chunk e.g. given by a call argument. Then configure the apache user's cron to run the script for each of the required modules (or even one for each chunk of records if you want to have more than one job running at a time, per module).
– Jay
Nov 18 '18 at 12:18
add a comment |
First of all I'd recommend finding out what part of the save takes so long, using the tool of your choice... profiler/debugger/custom Timers/etc.
- Is it a hook? Optimize it or make a custom flag to skip it if not needed for the recalc.
- Is it a query? Analyse the queries (
EXPLAIN
) to find out if adding indices to your database could help. - Is it excessive log output? Reduce it.
- Is it the bean loading for related bean calculation? Optimize formulas or skip if not needed.
Other things you could try:
- Prefilter which beans you want to resave using a Query (e.g. maybe record recalc not necessary if in certain state or modified after a certain related bean etc?).
- Trigger updating calculated fields in your code and check if (relevant) values of the bean where actually changed after, if not then there's no need to resave it and you can skip to the next record instead.
- If this is just about updating non-related calculated fields even although related calculated fields exist, then you could decide to (temporarily?) set
$sugar_config['disable_related_calc_fields']
to true. That way Sugar wouldn't have to load those related beans.
If there is no hope left:
- Consider running those tasks in parallel
- Rewrite whatever you need to update using SQL/SugarQuery (may not be possible, depending on complexity and implications).
Notes:
- Be aware that
get_full_list()
is deprecated since at least Sugar 7.7 and replaced by SugarQuery and$bean->fetchFromQuery()
. However I'd recommend using a Query to only retrieve the IDs and useBeanFactory::retrieveBean($module, $id)
to load the beans, possibly dismissing them each after computation, usingBeanFactory::unregisterBean($bean); unset($bean);
to help the garbage collector with keeping a low memory profile.
Also I did useget_full_list()
andfetchFromQuery
in the past with catastrophic side-effects due to beans not getting fully loaded when using that way instead of BeanFactory.
All records lost their email-addresses(!) as a result. I was not pleased. - Sugar 8: Especially if you have a lot of contacts, bad default indices on the table
erased_fields
will slow things down a lot as soon as it has a single record in it.erased_fields
only has a 2-column index by default (which isn't used in important queries though), so you'll have to add 2 individual indices for those 2 columns and things will be a lot faster again.
First of all I'd recommend finding out what part of the save takes so long, using the tool of your choice... profiler/debugger/custom Timers/etc.
- Is it a hook? Optimize it or make a custom flag to skip it if not needed for the recalc.
- Is it a query? Analyse the queries (
EXPLAIN
) to find out if adding indices to your database could help. - Is it excessive log output? Reduce it.
- Is it the bean loading for related bean calculation? Optimize formulas or skip if not needed.
Other things you could try:
- Prefilter which beans you want to resave using a Query (e.g. maybe record recalc not necessary if in certain state or modified after a certain related bean etc?).
- Trigger updating calculated fields in your code and check if (relevant) values of the bean where actually changed after, if not then there's no need to resave it and you can skip to the next record instead.
- If this is just about updating non-related calculated fields even although related calculated fields exist, then you could decide to (temporarily?) set
$sugar_config['disable_related_calc_fields']
to true. That way Sugar wouldn't have to load those related beans.
If there is no hope left:
- Consider running those tasks in parallel
- Rewrite whatever you need to update using SQL/SugarQuery (may not be possible, depending on complexity and implications).
Notes:
- Be aware that
get_full_list()
is deprecated since at least Sugar 7.7 and replaced by SugarQuery and$bean->fetchFromQuery()
. However I'd recommend using a Query to only retrieve the IDs and useBeanFactory::retrieveBean($module, $id)
to load the beans, possibly dismissing them each after computation, usingBeanFactory::unregisterBean($bean); unset($bean);
to help the garbage collector with keeping a low memory profile.
Also I did useget_full_list()
andfetchFromQuery
in the past with catastrophic side-effects due to beans not getting fully loaded when using that way instead of BeanFactory.
All records lost their email-addresses(!) as a result. I was not pleased. - Sugar 8: Especially if you have a lot of contacts, bad default indices on the table
erased_fields
will slow things down a lot as soon as it has a single record in it.erased_fields
only has a 2-column index by default (which isn't used in important queries though), so you'll have to add 2 individual indices for those 2 columns and things will be a lot faster again.
edited Nov 17 '18 at 12:05
answered Nov 17 '18 at 11:58
JayJay
1,346612
1,346612
Hi @Jay Thank you for your help! Could you please maybe tell me how is it possible to run these tasks in parallel ?
– Hamzaouiii
Nov 18 '18 at 12:06
@Hamzaouiii Well, that's outside the scope of Sugar and its Schedulers and should be only used as last resort (also it's not cloud-capable as it requires execution on the system level). You'd have to create a PHP script that loads in the sugar environment (similar to gist.github.com/bickart/5468138 ) before doing recalculations for a single module or chunk e.g. given by a call argument. Then configure the apache user's cron to run the script for each of the required modules (or even one for each chunk of records if you want to have more than one job running at a time, per module).
– Jay
Nov 18 '18 at 12:18
add a comment |
Hi @Jay Thank you for your help! Could you please maybe tell me how is it possible to run these tasks in parallel ?
– Hamzaouiii
Nov 18 '18 at 12:06
@Hamzaouiii Well, that's outside the scope of Sugar and its Schedulers and should be only used as last resort (also it's not cloud-capable as it requires execution on the system level). You'd have to create a PHP script that loads in the sugar environment (similar to gist.github.com/bickart/5468138 ) before doing recalculations for a single module or chunk e.g. given by a call argument. Then configure the apache user's cron to run the script for each of the required modules (or even one for each chunk of records if you want to have more than one job running at a time, per module).
– Jay
Nov 18 '18 at 12:18
Hi @Jay Thank you for your help! Could you please maybe tell me how is it possible to run these tasks in parallel ?
– Hamzaouiii
Nov 18 '18 at 12:06
Hi @Jay Thank you for your help! Could you please maybe tell me how is it possible to run these tasks in parallel ?
– Hamzaouiii
Nov 18 '18 at 12:06
@Hamzaouiii Well, that's outside the scope of Sugar and its Schedulers and should be only used as last resort (also it's not cloud-capable as it requires execution on the system level). You'd have to create a PHP script that loads in the sugar environment (similar to gist.github.com/bickart/5468138 ) before doing recalculations for a single module or chunk e.g. given by a call argument. Then configure the apache user's cron to run the script for each of the required modules (or even one for each chunk of records if you want to have more than one job running at a time, per module).
– Jay
Nov 18 '18 at 12:18
@Hamzaouiii Well, that's outside the scope of Sugar and its Schedulers and should be only used as last resort (also it's not cloud-capable as it requires execution on the system level). You'd have to create a PHP script that loads in the sugar environment (similar to gist.github.com/bickart/5468138 ) before doing recalculations for a single module or chunk e.g. given by a call argument. Then configure the apache user's cron to run the script for each of the required modules (or even one for each chunk of records if you want to have more than one job running at a time, per module).
– Jay
Nov 18 '18 at 12:18
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53344305%2fbean-save-is-taking-way-too-long-per-record-in-sugarcrm%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown