Needs review
Project:
OG User Roles
Version:
6.x-1.5
Component:
Code
Priority:
Normal
Category:
Bug report
Assigned:
Unassigned
Reporter:
Created:
28 Sep 2009 at 12:56 UTC
Updated:
11 Dec 2009 at 09:27 UTC
Currently, og_user_roles_user_manage() works by doing a db_query('SELECT uid FROM {users}') and user_load-ing every entry.
For medium and large sites, this means a totally unrealistic load both on the DB (one full scan table + n queries) and on the PHP (user_load-ing all user accounts).
The purpose of this code is to obtain a list of the accounts in groups managed by the current user, and only them, filtering achieved by an array_intersect() after building that monster list.
This should be done in a cheaper manner, and seems possible with just one query over the {og_uid} table.
Comments
Comment #1
sunWith the rise of the rewritten OGUR 4.x for Drupal 6, in which many unrelated features of OGUR were removed, and nearing a release of Drupal 7, I'm closing down old issues.
Comment #2
somebodysysop commentedCan you provde the query?
The person who changed the status of these issues to "won't fix" was not authorized to do so: http://drupal.org/node/352139#comment-2352234
OGUR 6.x-1.x will continue to be maintained by me.
Comment #3
fgmHi,
The problem is in og_user_roles_user_manage(). In version 1.1.2.15.2.31, it appears at lines 3130 to 3135. Quoting:
Notwithstanding the fact that it might make sense for this query to include a WHERE status=1 and a db_rewrite_sql($sql, 'u', 'uid') to allow for user-based access control, the performance issue lies in that :
user_load()in thewhileloop on all users in the system, causing, for each user a minimum of two additional queries in user_load():$result = db_query('SELECT * FROM {users} u WHERE '. implode(' AND ', $query), $params);andSELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d, plus invocations of the hook_user implementations for each user, meaning more code, and possibly even more queriesSince the call to that function starts with a given gid, it would probably be better to rethink the queries by starting from
{og_uid}or{og_users_roles}in order to limit the volume of data being handled.Comment #4
somebodysysop commentedAbsolutely sane idea. What about:
Comment #5
fgmLooks like a better start to me. Do you really need users with status=0 too ? And why don't you apply a db_rewrite_sql($sql, 'u', 'uid') in case someone has applied access control on user accounts ?
Comment #6
somebodysysop commentedWant to provide a code example?
Comment #7
fgmHow about this ?
Note that I removed the ORDER BY. With the current index structure, MySQL 5.1 uses a temporary and filesort to achieve that sort, whereas if you remove it, the query plan is optimal: ogu uses primary index with ref:const using index, and u uses primary index too, with ref ogu.uid and using where.
Since the query does not return the names, maybe it is not needed. At any rate, if name-based ordering is needing, it can be performed in PHP before rendering, which scales better.
Comment #8
somebodysysop commentedThis is great, thank you. One question: What happens if they are using a version of MySQL earlier than 5.1?
Comment #9
fgmI just checked, and exactly the same happens in 5.0: temp+filesort with the ORDER BY, and optimal without (tested on 5.0.51a-24+lenny2-log).