Details

    • Type: Improvement
    • Status: Development in progress
    • Priority: Minor
    • Resolution: Unresolved
    • Affects Version/s: 2.0, 2.3.2, 2.4, 2.8
    • Fix Version/s: DEV backlog
    • Component/s: Authentication
    • Labels:
    • Database:
      Any
    • Testing Instructions:
      Hide
      • You must have an external database with users
      • Enable auth/db
      • Configure the plugin to match you external database configs
      • Configure some profile fields to sync
        • Run the syncronization via cron
          • See that all users are imported much faster
      • Alter some details of your users in external database
        • Run the syncronization via cron
          • See that users you have altered are updated much faster

      You may have a somewhat big database, with at least 10K+ users to sync, to really see the difference in speed.

      Show
      You must have an external database with users Enable auth/db Configure the plugin to match you external database configs Configure some profile fields to sync Run the syncronization via cron See that all users are imported much faster Alter some details of your users in external database Run the syncronization via cron See that users you have altered are updated much faster You may have a somewhat big database, with at least 10K+ users to sync, to really see the difference in speed.
    • Affected Branches:
      MOODLE_20_STABLE, MOODLE_23_STABLE, MOODLE_24_STABLE, MOODLE_28_STABLE
    • Pull Master Branch:
      MDL-25373-master

      Description

      This patch does two things for auth/db:

      • Faster user sync
        • Use temporary tables to store all users with all fields
        • Select which users to update/insert/revive using (left) joins
        • Update user info using only one UPDATE statemente (instead of 1 udpate for each field for each user)

        Gliffy Diagrams

          Issue Links

            Activity

            Hide
            danielneis Daniel Neis added a comment -

            Hello, i've setup a git reposiroty in github, and now you can see the last version of patch at https://github.com/danielneis/moodle/compare/master...MDL-25373
            Add .patch or .diff if you want a plain text version

            Show
            danielneis Daniel Neis added a comment - Hello, i've setup a git reposiroty in github, and now you can see the last version of patch at https://github.com/danielneis/moodle/compare/master...MDL-25373 Add .patch or .diff if you want a plain text version
            Hide
            skodak Petr Skoda added a comment -

            Hello,

            your patch might cause a small regressions because some people want to run the external DB in read only more. The best solution would be probably to add new plugin setting which enables this functionality.

            Thanks for the patch.

            Petr

            Show
            skodak Petr Skoda added a comment - Hello, your patch might cause a small regressions because some people want to run the external DB in read only more. The best solution would be probably to add new plugin setting which enables this functionality. Thanks for the patch. Petr
            Hide
            danielneis Daniel Neis added a comment -

            Hello,

            i've updated the code in github. Sorry for the delay, but i had some problems with password reset here in tracker.

            Thanks for you quick response =)

            Best regards,
            Daniel

            Show
            danielneis Daniel Neis added a comment - Hello, i've updated the code in github. Sorry for the delay, but i had some problems with password reset here in tracker. Thanks for you quick response =) Best regards, Daniel
            Hide
            skodak Petr Skoda added a comment -

            Looks ok now, I will get it in right after we switch to git and the new review process (later this month).
            thanks a lot

            Show
            skodak Petr Skoda added a comment - Looks ok now, I will get it in right after we switch to git and the new review process (later this month). thanks a lot
            Hide
            danielneis Daniel Neis added a comment -

            Hello,

            i've updated the patch to solve both this issue and MDL-25372. Please take a look at https://github.com/danielneis/moodle/compare/master...MDL-25372

            Show
            danielneis Daniel Neis added a comment - Hello, i've updated the patch to solve both this issue and MDL-25372 . Please take a look at https://github.com/danielneis/moodle/compare/master...MDL-25372
            Hide
            aborrow Anthony Borrow added a comment -

            Thanks Daniel for providing a patch. With your work in Git I am hoping a developer might be willing to pick this up and evaluate it. Peace - Anthony

            Show
            aborrow Anthony Borrow added a comment - Thanks Daniel for providing a patch. With your work in Git I am hoping a developer might be willing to pick this up and evaluate it. Peace - Anthony
            Hide
            danielneis Daniel Neis added a comment -

            Hello,

            i've updated the patch to Moodle 2.2 STABLE:

            https://github.com/danielneis/moodle/compare/MOODLE_22_STABLE...MDL-25373

            Hope you like!

            Show
            danielneis Daniel Neis added a comment - Hello, i've updated the patch to Moodle 2.2 STABLE: https://github.com/danielneis/moodle/compare/MOODLE_22_STABLE...MDL-25373 Hope you like!
            Hide
            danielneis Daniel Neis added a comment -

            Hello,

            i've rebased the patch to current MOODLE_22_STABLE.
            I can get the code at the same URL as last comment ( https://github.com/danielneis/moodle/compare/MOODLE_22_STABLE...MDL-25373 ). This new version has updates in only one query (instead of one update for each field for each user) and does not support a separate table for password updates anymore because MySQL now implements updatable views...

            Hope you like,
            Daniel

            Show
            danielneis Daniel Neis added a comment - Hello, i've rebased the patch to current MOODLE_22_STABLE. I can get the code at the same URL as last comment ( https://github.com/danielneis/moodle/compare/MOODLE_22_STABLE...MDL-25373 ). This new version has updates in only one query (instead of one update for each field for each user) and does not support a separate table for password updates anymore because MySQL now implements updatable views... Hope you like, Daniel
            Hide
            danielneis Daniel Neis added a comment -

            Hello,

            i've rebased the patch to current MOODLE_23_STABLE : https://github.com/danielneis/moodle/compare/MOODLE_23_STABLE...MDL-25373-v23

            Hope you like,
            Daniel

            Show
            danielneis Daniel Neis added a comment - Hello, i've rebased the patch to current MOODLE_23_STABLE : https://github.com/danielneis/moodle/compare/MOODLE_23_STABLE...MDL-25373-v23 Hope you like, Daniel
            Hide
            danielneis Daniel Neis added a comment -

            I've updated the code for 2.3.2
            Hope you like!

            Show
            danielneis Daniel Neis added a comment - I've updated the code for 2.3.2 Hope you like!
            Hide
            epsd John Stabinger added a comment -

            I get these errors with the code and 2.3.2:

            PHP Notice: Undefined index: username in /var/online/auth/db/auth.php on line 332

            Notice: Undefined index: username in /var/online/auth/db/auth.php on line 332
            PHP Notice: Undefined index: username in /var/online/auth/db/auth.php on line 332

            Notice: Undefined index: username in /var/online/auth/db/auth.php on line 332
            ++ database_manager::drop_temp_table() is deprecated, use database_manager::drop_table() instead ++

            • line 461 of /lib/ddl/database_manager.php: call to debugging()
            • line 340 of /auth/db/auth.php: call to database_manager->drop_temp_table()
            • line 91 of /auth/db/cli/sync_users.php: call to auth_plugin_db->sync_users()
              Problem inserting records. Aborting!
            Show
            epsd John Stabinger added a comment - I get these errors with the code and 2.3.2: PHP Notice: Undefined index: username in /var/online/auth/db/auth.php on line 332 Notice: Undefined index: username in /var/online/auth/db/auth.php on line 332 PHP Notice: Undefined index: username in /var/online/auth/db/auth.php on line 332 Notice: Undefined index: username in /var/online/auth/db/auth.php on line 332 ++ database_manager::drop_temp_table() is deprecated, use database_manager::drop_table() instead ++ line 461 of /lib/ddl/database_manager.php: call to debugging() line 340 of /auth/db/auth.php: call to database_manager->drop_temp_table() line 91 of /auth/db/cli/sync_users.php: call to auth_plugin_db->sync_users() Problem inserting records. Aborting!
            Hide
            danielneis Daniel Neis added a comment -

            Helo, John

            about the "undefined index", are you sure you correctly configured the plugin at moodle/admin/auth_config.php?auth=db ?

            About the deprecated function, i've fixed it and updated the branch:

            https://github.com/danielneis/moodle/tree/MDL-25373-v232

            And here is the full diff:

            https://github.com/danielneis/moodle/compare/MOODLE_23_STABLE...MDL-25373-v232

            HTH,
            Daniel

            Show
            danielneis Daniel Neis added a comment - Helo, John about the "undefined index", are you sure you correctly configured the plugin at moodle/admin/auth_config.php?auth=db ? About the deprecated function, i've fixed it and updated the branch: https://github.com/danielneis/moodle/tree/MDL-25373-v232 And here is the full diff: https://github.com/danielneis/moodle/compare/MOODLE_23_STABLE...MDL-25373-v232 HTH, Daniel
            Hide
            poltawski Dan Poltawski added a comment -

            Putting this on my list to peer review, sorry your patch has been hanging around for so long.

            Thanks a lot for your collaboration!

            Show
            poltawski Dan Poltawski added a comment - Putting this on my list to peer review, sorry your patch has been hanging around for so long. Thanks a lot for your collaboration!
            Hide
            poltawski Dan Poltawski added a comment -

            Sending all 'waiting for peer review' issues to integration before freeze, as agreed in Integrators Meeting 19/10/12. We are doing this to ensure any 'integratable issues' will not got missed before freeze..

            Show
            poltawski Dan Poltawski added a comment - Sending all 'waiting for peer review' issues to integration before freeze, as agreed in Integrators Meeting 19/10/12. We are doing this to ensure any 'integratable issues' will not got missed before freeze..
            Hide
            poltawski Dan Poltawski added a comment -

            (This issue needs peer review first)

            Show
            poltawski Dan Poltawski added a comment - (This issue needs peer review first)
            Hide
            poltawski Dan Poltawski added a comment -

            Petr has been maintaining this area recently. Petr - wondering if you can find some time to have a look at the basis of the patch (i'm sure it'll need updating, its been on our queue for far too long )

            Show
            poltawski Dan Poltawski added a comment - Petr has been maintaining this area recently. Petr - wondering if you can find some time to have a look at the basis of the patch (i'm sure it'll need updating, its been on our queue for far too long )
            Hide
            josengfcorrea José Norberto Guiz Fernandes Corrêa added a comment -

            Hi there!

            I've updated the patch to MOODLE_24_STABLE. It's available at https://github.com/josenorberto/moodle/tree/MDL-25373_24

            Best regards,

            José Norberto

            Show
            josengfcorrea José Norberto Guiz Fernandes Corrêa added a comment - Hi there! I've updated the patch to MOODLE_24_STABLE. It's available at https://github.com/josenorberto/moodle/tree/MDL-25373_24 Best regards, José Norberto
            Hide
            skodak Petr Skoda added a comment -

            I have quickly looked at the patch and found a few issues:

            1/ it is most probably outdated, this would have to be master only I am afraid
            2/ we have just discovered performance problems with large temp tables in PostgreSQL, would this be also affected?
            3/ commit messages should not start with ":" after MDL issue
            4/ I do not like the changes in user_login() at all, it needs a separate issue and it should not duplicate the current code - it would rquire unit tests
            5/ mysql_escape_string() must not be used
            6/ please use code checker (capital letters, ///, whitespace, etc.)
            7/ if (delete_user($user)) - do not waste time checking result, it throws exception on error
            8/ use new $trace->output()
            9/ I am not sure we need to add so many new lang strings
            10/ new validations such as if (!validate_email($user->email)) need separate discussion imo
            11/ the username case is a tricky topic, forcing lowercase may break things badly, it needs a separate discussion - I personally think we should store the original value and only do the lowercasing on login and when adding manual accounts

            Anyway thanks for the patch.

            Show
            skodak Petr Skoda added a comment - I have quickly looked at the patch and found a few issues: 1/ it is most probably outdated, this would have to be master only I am afraid 2/ we have just discovered performance problems with large temp tables in PostgreSQL, would this be also affected? 3/ commit messages should not start with ":" after MDL issue 4/ I do not like the changes in user_login() at all, it needs a separate issue and it should not duplicate the current code - it would rquire unit tests 5/ mysql_escape_string() must not be used 6/ please use code checker (capital letters, ///, whitespace, etc.) 7/ if (delete_user($user)) - do not waste time checking result, it throws exception on error 8/ use new $trace->output() 9/ I am not sure we need to add so many new lang strings 10/ new validations such as if (!validate_email($user->email)) need separate discussion imo 11/ the username case is a tricky topic, forcing lowercase may break things badly, it needs a separate discussion - I personally think we should store the original value and only do the lowercasing on login and when adding manual accounts Anyway thanks for the patch.
            Hide
            mr-russ Russell Smith added a comment -

            Based on Petr's comment, I've added a relationship to the PostgreSQL temp table issue.

            Show
            mr-russ Russell Smith added a comment - Based on Petr's comment, I've added a relationship to the PostgreSQL temp table issue.
            Hide
            danielneis Daniel Neis added a comment - - edited

            Hello,

            I've rebased the code to lastest master, fixed the coding style and converted the code to use progress_trace.

            About large temporary tables, with MySQL you can tune how large these tables can grow into memory before going to disk. Here at Universidade Federal de Santa Catarina we have some external user tables with 30K+ users and the time dropped from 3 hours to about 30 seconds. We made the temporary tables big enough and does not use text or blob field types that forces temporary table to be created on disk.

            Hope you like,
            Daniel

            Show
            danielneis Daniel Neis added a comment - - edited Hello, I've rebased the code to lastest master, fixed the coding style and converted the code to use progress_trace. About large temporary tables, with MySQL you can tune how large these tables can grow into memory before going to disk. Here at Universidade Federal de Santa Catarina we have some external user tables with 30K+ users and the time dropped from 3 hours to about 30 seconds. We made the temporary tables big enough and does not use text or blob field types that forces temporary table to be created on disk. Hope you like, Daniel
            Show
            cibot CiBoT added a comment - Results for MDL-25373 Remote repository: https://github.com/danielneis/moodle Remote branch MDL-25373 to be integrated into upstream master Executed job http://integration.moodle.org/job/Precheck%20remote%20branch/3094 Details: http://integration.moodle.org/job/Precheck%20remote%20branch/3094/artifact/work/smurf.html
            Show
            cibot CiBoT added a comment - Results for MDL-25373 Remote repository: https://github.com/danielneis/moodle Remote branch MDL-25373 to be integrated into upstream master Executed job http://integration.moodle.org/job/Precheck%20remote%20branch/3234 Details: http://integration.moodle.org/job/Precheck%20remote%20branch/3234/artifact/work/smurf.html
            Hide
            danielneis Daniel Neis added a comment -

            Hello,

            i've updated the code to current master.
            Hope that you like.

            Kind regards,
            Daniel

            Show
            danielneis Daniel Neis added a comment - Hello, i've updated the code to current master. Hope that you like. Kind regards, Daniel
            Hide
            cibot CiBoT added a comment -

            Fails against automated checks.

            Checked MDL-25373 using repository: https://github.com/danielneis/moodle

            More information about this report

            Show
            cibot CiBoT added a comment - Fails against automated checks. Checked MDL-25373 using repository: https://github.com/danielneis/moodle master (branch: MDL-25373 | CI Job ) Testing instructions are missing. More information about this report
            Hide
            marina Marina Glancy added a comment - - edited

            I've removed Petr Skoda from the peer reviewer for this issue because it was left unattended for a long time

            Show
            marina Marina Glancy added a comment - - edited I've removed Petr Skoda from the peer reviewer for this issue because it was left unattended for a long time
            Hide
            fred Frédéric Massart added a comment -

            Many thanks everyone,

            A lot of work has been put into this, thank you! I had a look at the patch and here is what I could identify:

            1. I don't think we should be using language strings with $trace, but even if we do the language strings should come from auth_db, not auth_ws.
              • Also string codes should usually not contain underscores.
            2. $selarray is used before it is declared.
            3. Could we simplify the logic to use arrays for all the fields required to select/add/update, and at the last moment implode them?
            4. I am not a fan of adding raw SQL from the config properties, could we at least enforce the preg_match not to match .* but a limited set of characters?
            5. Are we sure that a field of type CHAR with a limit of 100 characters is enough? I think that the description field could be much bigger than that.
            6. Please do not write multiple unset() on the same line, rather you could call unset() with multiple arguments.
            7. I believe we could use get_recordset() where relevant when looping over a potentially large set of records.
            8. When reviving the users, shouldn't you only select the ones that are currently suspended?
              • Move over, when updating the users, shouldn't we set the field suspended to 0?
              • Why using the nologin authentication type in the query?
            9. I don't see any code that follows field_updatelocal, previously we would only update the records if it was set to onlogin.
            10. It might be more reliable cross DB to do an UPDATE with a sub select rather than an UPDATE with a JOIN. But I am not sure, can you confirm?
            11. I might be missing something but if you revive the accounts, why do we have to handle suspended accounts again in the '// Create missing accounts' block? Technically a missing account should not be suspended.
            12. You seem to be solving a different issue with the calendartype line that you added. I think it would be better to raise an issue for this.
            13. Coding style issue on L490 (space after the method name insert_record()).
            14. Our coding style suggests a commit message as described in this link, but that is trivial really. https://docs.moodle.org/dev/Commit_cheat_sheet#Provide_clear_commit_messages
            15. You might want to have a look at the existing Unit Tests, checking that they pass and that they cover what you'd expect.

            Sorry this review took so long but this issue will now be resolved soon. Daniel Neis I fully understand if you do not wish to pursue your work here, or if you simply do not have time. I will leave this issue as is for a couple of days to give everyone a chance to answer. Then I will happily take over the remaining work if need be.

            Thank you!
            Fred

            Show
            fred Frédéric Massart added a comment - Many thanks everyone, A lot of work has been put into this, thank you! I had a look at the patch and here is what I could identify: I don't think we should be using language strings with $trace, but even if we do the language strings should come from auth_db, not auth_ws. Also string codes should usually not contain underscores. $selarray is used before it is declared. Could we simplify the logic to use arrays for all the fields required to select/add/update, and at the last moment implode them? I am not a fan of adding raw SQL from the config properties, could we at least enforce the preg_match not to match .* but a limited set of characters? Are we sure that a field of type CHAR with a limit of 100 characters is enough? I think that the description field could be much bigger than that. Please do not write multiple unset() on the same line, rather you could call unset() with multiple arguments. I believe we could use get_recordset() where relevant when looping over a potentially large set of records. When reviving the users, shouldn't you only select the ones that are currently suspended? Move over, when updating the users, shouldn't we set the field suspended to 0? Why using the nologin authentication type in the query? I don't see any code that follows field_updatelocal , previously we would only update the records if it was set to onlogin . It might be more reliable cross DB to do an UPDATE with a sub select rather than an UPDATE with a JOIN. But I am not sure, can you confirm? I might be missing something but if you revive the accounts, why do we have to handle suspended accounts again in the '// Create missing accounts' block? Technically a missing account should not be suspended. You seem to be solving a different issue with the calendartype line that you added. I think it would be better to raise an issue for this. Coding style issue on L490 (space after the method name insert_record() ). Our coding style suggests a commit message as described in this link, but that is trivial really. https://docs.moodle.org/dev/Commit_cheat_sheet#Provide_clear_commit_messages You might want to have a look at the existing Unit Tests, checking that they pass and that they cover what you'd expect. Sorry this review took so long but this issue will now be resolved soon. Daniel Neis I fully understand if you do not wish to pursue your work here, or if you simply do not have time. I will leave this issue as is for a couple of days to give everyone a chance to answer. Then I will happily take over the remaining work if need be. Thank you! Fred
            Hide
            danielneis Daniel Neis added a comment -

            Hello, Frédéric

            thank you for the review!

            1. Removed get_string from trace->output
            2. Declared $selarray
            3. Could you please do that? =)
            4. Could you please point what line it is done?
            5. The best option would be to use the same type and size that Moodle's user table uses for each field. It may not be that hard to do.
            6. Fixed unset.
            7. Agree, but have not changed.
            8. Fixed to use suspended instead of nologin auth type
            9. Yes, this versions always updates user records (we may change this), but also the code for field_updatelocal is on update_user_record to update on login (i guess)
            10. I can not confirm this cross db issue, we may need someone with postgres background here, but i would prefer JOINs then subqueries.
            11. I got confused. One of them can certainly be removed. Would like a reviewer to do this =P
            12. This calendar type wasn't already there? Anyway, i think it ok to add it here, but i can open another issue to fix only that, but again i think it could be solved here =)
            13. Fixed
            14. Fixed
            15. I will take a look at unit tests. They are not run by the cibot?

            Also, after getting this on core, we will be able to compare it with LDAP and other auth methods and refactor a lot of repeated code

            Kind regards,
            Daniel

            Show
            danielneis Daniel Neis added a comment - Hello, Frédéric thank you for the review! 1. Removed get_string from trace->output 2. Declared $selarray 3. Could you please do that? =) 4. Could you please point what line it is done? 5. The best option would be to use the same type and size that Moodle's user table uses for each field. It may not be that hard to do. 6. Fixed unset. 7. Agree, but have not changed. 8. Fixed to use suspended instead of nologin auth type 9. Yes, this versions always updates user records (we may change this), but also the code for field_updatelocal is on update_user_record to update on login (i guess) 10. I can not confirm this cross db issue, we may need someone with postgres background here, but i would prefer JOINs then subqueries. 11. I got confused. One of them can certainly be removed. Would like a reviewer to do this =P 12. This calendar type wasn't already there? Anyway, i think it ok to add it here, but i can open another issue to fix only that, but again i think it could be solved here =) 13. Fixed 14. Fixed 15. I will take a look at unit tests. They are not run by the cibot? Also, after getting this on core, we will be able to compare it with LDAP and other auth methods and refactor a lot of repeated code Kind regards, Daniel
            Hide
            fred Frédéric Massart added a comment -

            Hi Daniel,

            while looking at what was left to be done on the issue, which I would do, I realised that I missed a few points during my first review. Correct me if I am wrong, but it seems that the performance gain is mostly due to the direct database update of the user records. However, this is not the way it should be done. The lower API user_create_record and user_update_record must be called because its logic is important, such as triggering events.

            I also noticed that the copy of all the user records over to the temp table is sometimes an unnecessary overhead when the sync was only creating missing users, or deleting them. If you do not wish to update the user records, it would still copy over all the records from the external database.

            Meantime, I feel sorry but I will send this issue back to developer so that we can try to find a solution for those points.

            Many thanks!
            Fred

            Show
            fred Frédéric Massart added a comment - Hi Daniel, while looking at what was left to be done on the issue, which I would do, I realised that I missed a few points during my first review. Correct me if I am wrong, but it seems that the performance gain is mostly due to the direct database update of the user records. However, this is not the way it should be done. The lower API user_create_record and user_update_record must be called because its logic is important, such as triggering events. I also noticed that the copy of all the user records over to the temp table is sometimes an unnecessary overhead when the sync was only creating missing users, or deleting them. If you do not wish to update the user records, it would still copy over all the records from the external database. Meantime, I feel sorry but I will send this issue back to developer so that we can try to find a solution for those points. Many thanks! Fred
            Hide
            damyon Damyon Wiese added a comment -

            Hi Daniel,

            I talked this issue over with Fred and I feel that this solution is probably a good fit for how you are using this external db sync - but that this solution would be worse for many users because of the speed of importing all records to a temporary table, temporary table support with different DB engines and tuning required for them, and the side effects from not using the user api for the create/update calls (and so not purging caches, triggering events etc).

            Once we change this patch to not perform the update with direct SQL and instead use the proper API, I'm not sure how much of a performance improvement would be left here.

            Show
            damyon Damyon Wiese added a comment - Hi Daniel, I talked this issue over with Fred and I feel that this solution is probably a good fit for how you are using this external db sync - but that this solution would be worse for many users because of the speed of importing all records to a temporary table, temporary table support with different DB engines and tuning required for them, and the side effects from not using the user api for the create/update calls (and so not purging caches, triggering events etc). Once we change this patch to not perform the update with direct SQL and instead use the proper API, I'm not sure how much of a performance improvement would be left here.
            Hide
            danielneis Daniel Neis added a comment -

            Hi, everybody

            as this issue was create on 22/Nov/10 (almost 4 years ago , this patch really didn't know anything about events, or triggers or anything else.
            Also, about the speed of importing all records to a temporary table, for sure it can be a huge impairment, but if you have a big database and rely on Moodle current code you are currently facing a worse case.

            The main point of the patch is that you do not do "1 external select + 1 internal update" for each field for each user.
            In the current patch you could add a query to select which users will be update, prior to updating, and then you trigger the event updates after update everybody with just one query. It will be 2 queries versus "2*fields_count*users_count".

            Also, for user creation, you can change the insert_record with the user_create_user function, no problems

            Show
            danielneis Daniel Neis added a comment - Hi, everybody as this issue was create on 22/Nov/10 (almost 4 years ago , this patch really didn't know anything about events, or triggers or anything else. Also, about the speed of importing all records to a temporary table, for sure it can be a huge impairment, but if you have a big database and rely on Moodle current code you are currently facing a worse case. The main point of the patch is that you do not do "1 external select + 1 internal update" for each field for each user. In the current patch you could add a query to select which users will be update, prior to updating, and then you trigger the event updates after update everybody with just one query. It will be 2 queries versus "2*fields_count*users_count". Also, for user creation, you can change the insert_record with the user_create_user function, no problems

              People

              • Votes:
                5 Vote for this issue
                Watchers:
                11 Start watching this issue

                Dates

                • Created:
                  Updated: