From c6df8c2e6d3b7b33166901857b60168605ca81d7 Mon Sep 17 00:00:00 2001
From: Matt Clarkson <mattc@catalyst.net.nz>
Date: Fri, 25 May 2012 10:42:33 +1200
Subject: [PATCH 1/1] lib/navigationlib: Preload contexts to reduce query
 count

With a large category tree and navshowcategories set there were hundreds
of queries being done to load the context instance of each course
category.
---
 lib/navigationlib.php |   43 +++++++++++++++++++++++++++++--------------
 1 file changed, 29 insertions(+), 14 deletions(-)

diff --git a/lib/navigationlib.php b/lib/navigationlib.php
index bc68711..a431bc0 100644
--- a/lib/navigationlib.php
+++ b/lib/navigationlib.php
@@ -1459,26 +1459,35 @@ class global_navigation extends navigation_node {
         }
 
         $coursestoload = array();
+        $cxfields = context_helper::get_preload_record_columns_sql('cx');
+
         if (empty($categoryid)) { // can be 0
             // We are going to load all of the first level categories (categories without parents)
-            $categories = $DB->get_records('course_categories', array('parent'=>'0'), 'sortorder ASC, id ASC');
+            $sql = "SELECT cc.*, $cxfields
+                    FROM {course_categories} cc
+                        INNER JOIN {context} cx ON cc.id = cx.instanceid AND cx.contextlevel = ".CONTEXT_COURSECAT."
+                    WHERE parent = 0
+                    ORDER BY sortorder ASC, id ASC";
+            $categories = $DB->get_records_sql($sql);
         } else if (array_key_exists($categoryid, $this->addedcategories)) {
             // The category itself has been loaded already so we just need to ensure its subcategories
             // have been loaded
             list($sql, $params) = $DB->get_in_or_equal(array_keys($this->addedcategories), SQL_PARAMS_NAMED, 'parent', false);
             if ($showbasecategories) {
                 // We need to include categories with parent = 0 as well
-                $sql = "SELECT *
-                          FROM {course_categories} cc
-                         WHERE (parent = :categoryid OR parent = 0) AND
-                               parent {$sql}
-                      ORDER BY depth DESC, sortorder ASC, id ASC";
+                $sql = "SELECT cc.*, $cxfields
+                        FROM {course_categories} cc
+                            INNER JOIN {context} cx ON cc.id = cx.instanceid AND cx.contextlevel = ".CONTEXT_COURSECAT."
+                        WHERE (parent = :categoryid OR parent = 0) AND
+                            parent {$sql}
+                        ORDER BY depth DESC, sortorder ASC, id ASC";
             } else {
-                $sql = "SELECT *
-                          FROM {course_categories} cc
-                         WHERE parent = :categoryid AND
-                               parent {$sql}
-                      ORDER BY depth DESC, sortorder ASC, id ASC";
+                $sql = "SELECT cc.*, $cxfields
+                        FROM {course_categories} cc
+                            INNER JOIN {context} cx ON cc.id = cx.instanceid AND cx.contextlevel = ".CONTEXT_COURSECAT."
+                        WHERE parent = :categoryid AND
+                            parent {$sql}
+                        ORDER BY depth DESC, sortorder ASC, id ASC";
             }
             $params['categoryid'] = $categoryid;
             $categories = $DB->get_records_sql($sql, $params);
@@ -1492,12 +1501,17 @@ class global_navigation extends navigation_node {
             $category = $DB->get_record('course_categories', array('id' => $categoryid), 'path', MUST_EXIST);
             $coursestoload = explode('/', trim($category->path, '/'));
             list($select, $params) = $DB->get_in_or_equal($coursestoload);
-            $select = 'id '.$select.' OR parent '.$select;
+            $select = 'cc.id '.$select.' OR cc.parent '.$select;
             if ($showbasecategories) {
-                $select .= ' OR parent = 0';
+                $select .= ' OR cc.parent = 0';
             }
+            $sql = "SELECT cc.*, $cxfields
+                      FROM {course_categories} cc
+                      INNER JOIN {context} cx ON cc.id = cx.instanceid AND cx.contextlevel = ".CONTEXT_COURSECAT."
+                    WHERE $select
+                    ORDER BY depth DESC, sortorder ASC, id ASC";
             $params = array_merge($params, $params);
-            $categories = $DB->get_records_select('course_categories', $select, $params, 'sortorder');
+            $categories = $DB->get_records_sql($sql, $params);
         }
 
         // Now we have an array of categories we need to add them to the navigation.
@@ -1554,6 +1568,7 @@ class global_navigation extends navigation_node {
             return;
         }
         $url = new moodle_url('/course/category.php', array('id' => $category->id));
+        context_helper::preload_from_record($category);
         $context = get_context_instance(CONTEXT_COURSECAT, $category->id);
         $categoryname = format_string($category->name, true, array('context' => $context));
         $categorynode = $parent->add($categoryname, $url, self::TYPE_CATEGORY, $categoryname, $category->id);
-- 
1.7.10

