我已经建立了一个CMS系统,其中有一个相当典型的用户/组/权限系统,用户可以成为组的成员,并且权限可以直接应用于用户,也可以应用于用户可以成为成员的组。权限还可以是“通配符”(例如应用于所有对象),或者应用于由模块名称和行ID指定的特定对象。权限可以是“允许”(即授权访问)或“拒绝”,后者专门阻止访问并覆盖他们在其他地方被授予的任何“允许”权限。拒绝通过创建带有“allow”列设置为0的行来存储在userpermission/grouppermission表中。
以下查询目前被使用(并有效)来列出所有已被授予特定“通配符”权限(permissionid 123)的用户。
然而,它非常缓慢(~0.5秒,约有3000个用户,250个组,10000个用户组加入,30个权限,150个组权限和30个用户权限)。
如上例所示,permissionid只是一个权限。可能需要检查多个权限,例如
解释提供以下输出-我认为我已经正确索引了列,但我不确定如何(或是否可能)索引派生表:
如果需要更改数据结构,则并不是一个巨大的问题。
以下查询目前被使用(并有效)来列出所有已被授予特定“通配符”权限(permissionid 123)的用户。
SELECT
`user`.*
FROM
(
SELECT
`user`.*,
`userpermission`.`allow` AS `user_allow`,
`userpermission`.`permissionid` AS `user_permissionid`,
`grouppermission`.`allow` AS `group_allow`,
`grouppermission`.`permissionid` AS `group_permissionid`
FROM
`user`
LEFT JOIN `userpermission` ON
`user`.`userid` = `userpermission`.`userid`
AND `userpermission`.`module` = '*'
AND `userpermission`.`rowid` = '*'
AND `userpermission`.`permissionid` = 18
LEFT JOIN `usergroup` ON
`user`.`userid` = `usergroup`.`userid`
LEFT JOIN `grouppermission` ON
`usergroup`.`groupid` = `grouppermission`.`groupid`
AND `grouppermission`.`module` = '*'
AND `grouppermission`.`rowid` = '*'
AND `grouppermission`.`permissionid` = 18
WHERE
(
`grouppermission`.`allow` = 1
OR
`userpermission`.`allow` = 1
)
) AS `user`
LEFT JOIN `userpermission` ON
`user`.`userid` = `userpermission`.`userid`
AND `userpermission`.`permissionid` = `user`.`user_permissionid`
AND `userpermission`.`allow` = 0
AND `userpermission`.`module` = '*'
AND `userpermission`.`rowid` = '*'
LEFT JOIN `usergroup` ON
`user`.`userid` = `usergroup`.`userid`
LEFT JOIN `grouppermission` ON
`usergroup`.`groupid` = `grouppermission`.`groupid`
AND `grouppermission`.`permissionid` = `user`.`group_permissionid`
AND `grouppermission`.`allow` = 0
AND `grouppermission`.`module` = '*'
AND `grouppermission`.`rowid` = '*'
GROUP BY `user`.`userid`
HAVING
COUNT(`userpermission`.`userpermissionid`) + COUNT(`grouppermission`.`grouppermissionid`) = 0
然而,它非常缓慢(~0.5秒,约有3000个用户,250个组,10000个用户组加入,30个权限,150个组权限和30个用户权限)。
如上例所示,permissionid只是一个权限。可能需要检查多个权限,例如
IN(18,19,20)
而不是=18
。解释提供以下输出-我认为我已经正确索引了列,但我不确定如何(或是否可能)索引派生表:
+----+-------------+-----------------+------+----------------------------+--------------+---------+--------------------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
| 1 | PRIMARY | [derived2] | ALL | NULL | NULL | NULL | NULL | 62 | Using temporary; Using filesort |
| 1 | PRIMARY | userpermission | ref | USERID,PERMISSIONID,ALLOW | USERID | 4 | user.userid | 2 | |
| 1 | PRIMARY | usergroup | ref | USERID | USERID | 4 | user.userid | 4 | |
| 1 | PRIMARY | grouppermission | ref | GROUPID,PERMISSIONID,ALLOW | PERMISSIONID | 4 | user.group_permissionid | 3 | |
| 2 | DERIVED | user | ALL | NULL | NULL | NULL | NULL | 2985 | |
| 2 | DERIVED | userpermission | ref | USERID,PERMISSIONID | PERMISSIONID | 4 | | 1 | |
| 2 | DERIVED | usergroup | ref | USERID | USERID | 4 | [database].user.userid | 4 | |
| 2 | DERIVED | grouppermission | ref | GROUPID,PERMISSIONID | PERMISSIONID | 4 | | 3 | Using where |
+----+-------------+-----------------+------+----------------------------+--------------+---------+--------------------------------+------+---------------------------------+
是否可以重写查询而不使用子查询,以便进行优化,或者按原样进行优化?如果需要更改数据结构,则并不是一个巨大的问题。