Skip to content
Snippets Groups Projects
Commit 38451e87 authored by Jan-Hendrik Willms's avatar Jan-Hendrik Willms
Browse files

optimize query that loads the courses by using a subselect and EXISTS and...

optimize query that loads the courses by using a subselect and EXISTS and avoid duplication of costly query, fixes #3999

Closes #3999

Merge request studip/studip!2905
parent 8b07f02f
No related branches found
No related tags found
No related merge requests found
...@@ -375,14 +375,14 @@ class Admin_CoursesController extends AuthenticatedController ...@@ -375,14 +375,14 @@ class Admin_CoursesController extends AuthenticatedController
} }
PluginEngine::sendMessage(AdminCourseWidgetPlugin::class, 'applyFilters', $filter); PluginEngine::sendMessage(AdminCourseWidgetPlugin::class, 'applyFilters', $filter);
$count = $filter->countCourses(); try {
if ($count > $this->max_show_courses && !Request::submitted('without_limit')) { $courses = $filter->fetchCourses(
$this->render_json([ Request::bool('without_limit') ? null: $this->max_show_courses
'count' => $count );
]); } catch (OverflowException $e) {
$this->render_json(['count' => (int) $e->getMessage()]);
return; return;
} }
$courses = AdminCourseFilter::get()->getCourses();
$data = [ $data = [
'data' => [] 'data' => []
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
class AdminCourseFilter class AdminCourseFilter
{ {
static protected $instance = null; static protected $instance = null;
/** @var SQLQuery|null */
public $query = null; public $query = null;
public $max_show_courses = 500; public $max_show_courses = 500;
public $settings = []; public $settings = [];
...@@ -109,13 +111,10 @@ class AdminCourseFilter ...@@ -109,13 +111,10 @@ class AdminCourseFilter
} }
if (Config::get()->ALLOW_ADMIN_RELATED_INST) { if (Config::get()->ALLOW_ADMIN_RELATED_INST) {
$sem_inst = 'seminar_inst'; $this->query->where('seminar_inst', 'EXISTS (SELECT 1 FROM seminar_inst WHERE seminar_id = seminare.Seminar_id AND institut_id IN (:institut_ids))');
$this->query->join('seminar_inst', 'seminar_inst', 'seminar_inst.seminar_id = seminare.Seminar_id');
} else { } else {
$sem_inst = 'seminare'; $this->query->where("seminar_inst", "seminare.institut_id IN (:institut_ids)");
} }
$this->query->where('seminar_inst', "$sem_inst.institut_id IN (:institut_ids)");
$this->query->parameter('institut_ids', $inst_ids); $this->query->parameter('institut_ids', $inst_ids);
if ($GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE) { if ($GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE) {
...@@ -195,6 +194,16 @@ class AdminCourseFilter ...@@ -195,6 +194,16 @@ class AdminCourseFilter
return $this->query->count(); return $this->query->count();
} }
/**
* @param int|null $limit
* @return Course[]
*/
public function fetchCourses(?int $limit = null): array
{
NotificationCenter::postNotification('AdminCourseFilterWillQuery', $this);
return $this->query->fetchAll(Course::class, $limit);
}
/** /**
* Returns the data of the resultset of the AdminCourseFilter. * Returns the data of the resultset of the AdminCourseFilter.
* *
...@@ -206,16 +215,16 @@ class AdminCourseFilter ...@@ -206,16 +215,16 @@ class AdminCourseFilter
*/ */
public function getCoursesForAdminWidget(string $order_by = 'name') public function getCoursesForAdminWidget(string $order_by = 'name')
{ {
$count_courses = $this->countCourses(); try {
$order = 'seminare.name'; $order = 'seminare.name';
if ($order_by === 'number') { if ($order_by === 'number') {
$order = 'seminare.veranstaltungsnummer, seminare.name'; $order = 'seminare.veranstaltungsnummer, seminare.name';
} }
if ($count_courses && $count_courses <= $this->max_show_courses) {
$this->query->orderBy($order); $this->query->orderBy($order);
return $this->getCourses(); return $this->fetchCourses($this->max_show_courses);
} catch (OverflowException $e) {
return [];
} }
return [];
} }
} }
...@@ -215,14 +215,22 @@ class SQLQuery ...@@ -215,14 +215,22 @@ class SQLQuery
/** /**
* Fetches the whole resultset as an array of associative arrays. If you define * Fetches the whole resultset as an array of associative arrays. If you define
* a sorm_class the result will be an array of the sorm-objects. * a sorm_class the result will be an array of the sorm-objects.
* @param $sorm_class_or_column : column name, a class of SimpleORMap or null for associative array. *
* @return array of arrays or array of objects or array of values. * @template T of SimpleORMap
* @param class-string<T>|string|null $sorm_class_or_column : column name, a class of SimpleORMap or null for associative array.
* @param int|null $max_results Maximum number of results to return
* @return array[]|T[]|mixed[] arrays or array of objects or array of values.
*
* @throws OverflowException if number of found rows is greater than $max_results
*/ */
public function fetchAll($sorm_class_or_column = null) public function fetchAll($sorm_class_or_column = null, ?int $max_results = null)
{ {
NotificationCenter::postNotification('SQLQueryWillExecute', $this); NotificationCenter::postNotification('SQLQueryWillExecute', $this);
if (is_string($sorm_class_or_column) && !is_subclass_of($sorm_class_or_column, "SimpleORMap")) { if (
is_string($sorm_class_or_column)
&& !is_subclass_of($sorm_class_or_column, SimpleORMap::class)
) {
$sql = "SELECT `{$this->settings['table']}`.`{$sorm_class_or_column}` "; $sql = "SELECT `{$this->settings['table']}`.`{$sorm_class_or_column}` ";
} else { } else {
$sql = "SELECT `{$this->settings['table']}`.* "; $sql = "SELECT `{$this->settings['table']}`.* ";
...@@ -239,16 +247,31 @@ class SQLQuery ...@@ -239,16 +247,31 @@ class SQLQuery
NotificationCenter::postNotification('SQLQueryDidExecute', $this); NotificationCenter::postNotification('SQLQueryDidExecute', $this);
if (is_string($sorm_class_or_column) && !is_subclass_of($sorm_class_or_column, "SimpleORMap")) { if (
return $statement->fetchAll(PDO::FETCH_COLUMN, 0); is_string($sorm_class_or_column)
&& !is_subclass_of($sorm_class_or_column, SimpleORMap::class)
) {
return $statement->fetchAll(PDO::FETCH_COLUMN);
} }
$alldata = $statement->fetchAll(PDO::FETCH_ASSOC); $statement->setFetchMode(PDO::FETCH_ASSOC);
if (!$sorm_class_or_column) {
return $alldata; $result = [];
$count = 0;
foreach ($statement as $row) {
$result[$count++] = $sorm_class_or_column ? $sorm_class_or_column::buildExisting($row) : $row;
if ($max_results && $count > $max_results) {
// Count remaining rows
$statement->setFetchMode(PDO::FETCH_COLUMN, 0);
while ($statement->fetch()) {
$count += 1;
}
throw new OverflowException($count);
}
} }
return array_map("{$sorm_class_or_column}::buildExisting", $alldata); return $result;
} }
/** /**
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment