The query in user_access() uses DISTINCT which is superfluous. On any properly setup Drupal site any two different roles will have different permissions.

The DISTINCT also makes the query slow since the permission strings can be quite long. The query shows up in the slow query log on drupal.org:

### 74 Queries
### Taking 16 to 21 seconds to complete

SELECT DISTINCT(p.perm) FROM role r INNER JOIN permission p ON p.rid = r.rid WHERE r.rid IN (XXX);

This is on the new, fast server, there have been more queries on the old one.

Even if there should be two roles with identical permissions, the new query won't break anything. The only thing which will happen is that the $perm static array will gain a few hundred bytes. This might slow down the strpos check later, but I'd argue that a site shouldn't have two roles with identical permissions.

Comments

robertdouglass’s picture

This raises several observations and questions.

First, I'm inclined to agree that the distinct can be dropped. If we have more than one row per rid in the permissions table, is that not an application error somewhere else? Even if we did, isn't that role entitled to all of those permissions? So the perm strings would be concatenated, split into an array, and an in_array would be done on it. Not catastrophic.

The first question I have when looking, though, is what does permission.tid do?
The second question I have is why are these two separate tables? Why is perm not a column of role?

killes@www.drop.org’s picture

Title: Remove DISTINCT in query » Tune user_access
StatusFileSize
new2.13 KB

tid can be dropped, not sure why it hasn't been. I've no idea why permissions is an extra table.

I've tuned the function some more. See attached test script.

I've found that using in_array is much faster.

killes@www.drop.org’s picture

StatusFileSize
new2.93 KB

Here's the improved patch.

killes@www.drop.org’s picture

StatusFileSize
new1.33 KB

More simplification.

killes@www.drop.org’s picture

StatusFileSize
new1.34 KB

The previous patch wasn't quite right and due to this in_array is actually faster than the current approach but if we restrict strpos to only act on unique permissions, we gain more.

killes@www.drop.org’s picture

StatusFileSize
new2.26 KB

Corrected test script.

chx’s picture

StatusFileSize
new1.15 KB

You stopped halfway.

killes@www.drop.org’s picture

Status: Needs review » Reviewed & tested by the community

Indeed, isset() is again much faster.

dries’s picture

Status: Reviewed & tested by the community » Fixed

Tested, looks good. Committed to CVS HEAD. Thanks.

chx’s picture

Version: 6.x-dev » 5.x-dev
Assigned: killes@www.drop.org » chx
Status: Fixed » Reviewed & tested by the community
StatusFileSize
new1.4 KB

This is useful for D5 as well.

robertdouglass’s picture

At what point should we decide to drop the tid column from permissions? Is there any reason these aren't combined into 1 table?

DrupalTestbedBot tested killes@www.drop.org's patch (http://drupal.org/files/issues/test_6.txt), the patch failed. For more information visit http://testing.drupal.org/node/97

DrupalTestbedBot tested killes@www.drop.org's patch (http://drupal.org/files/issues/tune_user_access.patch), the patch failed. For more information visit http://testing.drupal.org/node/98

DrupalTestbedBot tested killes@www.drop.org's patch (http://drupal.org/files/issues/tune_user_access_0.patch), the patch failed. For more information visit http://testing.drupal.org/node/99

robin monks’s picture

Sorry, seems some of these weren't really patches, but, the bot has no way to tell that.

drumm’s picture

Status: Reviewed & tested by the community » Needs work

Fatal error: Call to undefined function db_placeholders() in /home/drumm/drupal/c-5/modules/user/user.module on line 368

mot’s picture

Status: Needs work » Closed (fixed)

No activity since a lot time. Patch fails testing. Orphaned. Looks like this ain't an Issue any longer for the patcher. Closed.