Skip to content

Commit

Permalink
MDL-47426 assign local roles: rewrite query for better performance.
Browse files Browse the repository at this point in the history
This is an extremely dangerous query, because it includes the user
table twice, along-side two other potentially large tables,
role_assignments and user_enrolments.

The solution is to rewrite the query so that:

1. The subquery is JOINed, not WHERE ... INed. Typically query
   optimisers handle the JOIN case better.

2. Before the join was role-assignments <-> users <-> subquery.
   That is, everything was linked to u.id.

   Now the linking is role-assignments <-> subquery <-> users,
   so the SELECT DISTINT eu1_u.id FROM {enrolled users} is central.
   That seems to send a strong hint to the query optimiser about
   a good order to execute the query.
  • Loading branch information
timhunt committed Oct 2, 2014
1 parent 6597413 commit 482ca72
Showing 1 changed file with 6 additions and 5 deletions.
11 changes: 6 additions & 5 deletions admin/roles/classes/potential_assignees_below_course.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@ public function find_users($search) {
$fields = 'SELECT ' . $this->required_fields_sql('u');
$countfields = 'SELECT COUNT(u.id)';

$sql = " FROM {user} u
LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.roleid = :roleid AND ra.contextid = :contextid)
WHERE u.id IN ($enrolsql)
$wherecondition
AND ra.id IS NULL";
$sql = " FROM ($enrolsql) enrolled_users_view
JOIN {user} u ON u.id = enrolled_users_view.id
LEFT JOIN {role_assignments} ra ON (ra.userid = enrolled_users_view.id AND
ra.roleid = :roleid AND ra.contextid = :contextid)
WHERE ra.id IS NULL
$wherecondition";
$params['contextid'] = $this->context->id;
$params['roleid'] = $this->roleid;

Expand Down

0 comments on commit 482ca72

Please sign in to comment.