From 3a42d256afc049eb76dcc20447333cb3350eeb9d Mon Sep 17 00:00:00 2001 From: Huong Nguyen Date: Thu, 9 Sep 2021 09:33:15 +0700 Subject: [PATCH] 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() --- completion/classes/cm_completion_details.php | 4 +- lib/completionlib.php | 44 ++++++++------------ 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/completion/classes/cm_completion_details.php b/completion/classes/cm_completion_details.php index 4c299ed7694..d08196189a4 100644 --- a/completion/classes/cm_completion_details.php +++ b/completion/classes/cm_completion_details.php @@ -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; diff --git a/lib/completionlib.php b/lib/completionlib.php index 66d6556b1ec..eed0e751f8f 100644 --- a/lib/completionlib.php +++ b/lib/completionlib.php @@ -1055,39 +1055,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])) {