MDL-71899 performance: Improve activity completion data caching

- Modified SQL in get_data() to get the activity completion of all course modules without calling get_fast_modinfo() to reduce the DB queries.
 - Building activity completion cache for the whole course in one time instead of building the cache for each course module by passing $wholecourse = true to get_data()
This commit is contained in:
Huong Nguyen 2021-09-09 09:33:15 +07:00
parent e0dd5f268a
commit 3150612163
2 changed files with 20 additions and 28 deletions

View File

@ -65,7 +65,9 @@ class cm_completion_details {
*/
public function __construct(completion_info $completioninfo, cm_info $cminfo, int $userid, bool $returndetails = true) {
$this->completioninfo = $completioninfo;
$this->completiondata = $completioninfo->get_data($cminfo, false, $userid);
// We need to pass wholecourse = true here for better performance. All the course's completion data for the current
// logged-in user will get in a single query instead of multiple queries and loaded to cache.
$this->completiondata = $completioninfo->get_data($cminfo, true, $userid);
$this->cminfo = $cminfo;
$this->userid = $userid;
$this->returndetails = $returndetails;

View File

@ -1062,39 +1062,29 @@ class completion_info {
// Fetch completion data for all of the activities in the course ONLY if we're caching the fetched completion data.
// If we're not caching the completion data, then just fetch the completion data for the user in this course module.
if ($usecache && $wholecourse) {
// Get whole course data for cache
$alldatabycmc = $DB->get_records_sql("
SELECT
cmc.*
FROM
{course_modules} cm
INNER JOIN {course_modules_completion} cmc ON cmc.coursemoduleid=cm.id
WHERE
cm.course=? AND cmc.userid=?", array($this->course->id, $userid));
// Get whole course data for cache.
$alldatabycmc = $DB->get_records_sql("SELECT cm.id AS cmid, cmc.*
FROM {course_modules} cm
LEFT JOIN {course_modules_completion} cmc ON cmc.coursemoduleid = cm.id
AND cmc.userid = ?
INNER JOIN {modules} m ON m.id = cm.module
WHERE m.visible = 1 AND cm.course = ?", [$userid, $this->course->id]);
// Reindex by cm id
$alldata = array();
// Reindex by course module id.
foreach ($alldatabycmc as $data) {
$alldata[$data->coursemoduleid] = (array)$data;
}
// Get the module info and build up condition info for each one
if (empty($modinfo)) {
$modinfo = get_fast_modinfo($this->course, $userid);
}
foreach ($modinfo->cms as $othercm) {
if (isset($alldata[$othercm->id])) {
$data = $alldata[$othercm->id];
if (empty($data->coursemoduleid)) {
$cacheddata[$data->cmid] = $defaultdata;
$cacheddata[$data->cmid]['coursemoduleid'] = $data->cmid;
} else {
// Row not present counts as 'not complete'.
$data = $defaultdata;
$data['coursemoduleid'] = $othercm->id;
$cacheddata[$data->cmid] = (array) $data;
}
// Make sure we're working on a cm_info object.
$othercminfo = cm_info::create($othercm, $userid);
$cmstd = new stdClass();
$cmstd->id = $data->cmid;
$cmstd->course = $this->course->id;
$othercminfo = cm_info::create($cmstd, $userid);
// Add the other completion data for this user in this module instance.
$data += $this->get_other_cm_completion_data($othercminfo, $userid);
$cacheddata[$othercminfo->id] = $data;
$cacheddata[$othercminfo->id] += $this->get_other_cm_completion_data($othercminfo, $userid);
}
if (!isset($cacheddata[$cminfo->id])) {