I am encountering a performance issue on my Moodle site, which has courses with tens of thousands of users (ranging from 50,000 to 80,000 users per course), and the total number of users on the site exceeds 500,000. Our theme displays the count of users per course, and certain pages show more than 20 courses per page.
The problem arises when we have a high number of concurrent users, typically ranging from 1,000 to 2,000 users. It appears that the database becomes overloaded. Upon investigation, I found that the 'count_enrolled_users' function in the Moodle core, located in the file 'lib\enrollib', takes around 8 seconds to execute when there is high user concurrency. Consequently, this leads to numerous database threads, indicating that the enrollment count might need to be handled differently. One potential solution could be utilizing Moodle cache.
I would greatly appreciate it if anyone has any ideas or configurations that I could implement to overcome this issue. Should this be considered an enhancement request for Moodle core, or am I missing any specific configuration settings to handle a high number of concurrent users?
Below is the code for the aforementioned function and a section of a slow query for reference:
function count_enrolled_users(context $context, $withcapability = '', $groupid = 0, $onlyactive = false) {
global $DB;
$capjoin = get_enrolled_with_capabilities_join(
$context, '', $withcapability, $groupid, $onlyactive);
$sql = "SELECT COUNT(DISTINCT u.id)
FROM {user} u
$capjoin->joins
WHERE $capjoin->wheres AND u.deleted = 0";
return $DB->count_records_sql($sql, $capjoin->params);
}
Part of Slow Query Report
# User@Host: mahara[mahara] @ [10.144.243.99]
# Thread_id: 32 Schema: moodle QC_hit: No
# Query_time: 9.787826 Lock_time: 0.000050 Rows_sent: 1 Rows_examined: 128204
# Rows_affected: 0 Bytes_sent: 79
# Tmp_tables: 1 Tmp_disk_tables: 0 Tmp_table_sizes: 0
# Full_scan: No Full_join: No Tmp_table: Yes Tmp_table_on_disk: No
# Filesort: No Filesort_on_disk: No Merge_passes: 0 Priority_queue: No
SET timestamp=1686830092;
SELECT COUNT(DISTINCT u.id)
FROM mdl_user u
JOIN mdl_user_enrolments ej13_ue ON ej13_ue.userid = u.id
JOIN mdl_enrol ej13_e ON (ej13_e.id = ej13_ue.enrolid AND ej13_e.courseid = '7')
WHERE 1 = 1 AND u.deleted = 0 AND u.deleted = 0;
Any suggestions or insights would be greatly appreciated. Thank you in advance!