我正在实施以下访问策略:User
如果他创建了它,则可以访问Resource
,属于Resource
的组成员或资源是公共可用的。在两个索引+排序上的MySQL查询性能
这里是我的数据库结构(表是MyISAM数据):
User (1K-10K Users)
id
nickame
…
index user_name(id, nickname)
Group (1K)
id
…
Resource (10K-100K)
id
user_id
access_type (int)
group_id
created (int/timestamp)
…
indexes by_user(user_id, created), by_group(access_type, group_id, created), public(access_type, created)
User_Group (5K-20K)
user_id
group_id
membership_type (int)
index user_group(user_id, membership_type, group_id)
授予访问权的条件是这种方式实现的: *的User
是Resource
的创造者(user_id = <his id>
,无论ACCESS_TYPE是) *或者资源是公开可用的:Resource.access_id = 3
*或者资源在组中共享并且用户被接受为该组的成员: ** Resource.access_id = 2
(在组中共享) ** Ressource.group_id
匹配User_Group
的group_id
**这User_Group
的user_id
的用户的ID **匹配这个User_Group
的membership_type
是1,2或3(接受成员或组慢化剂/管理员)
我的问题是:什么是列出Resources
(和Resource
创建者的nickname
)最有效的方式,当我们有他的ID时,用户可以访问它。并按资源的created
时间戳排序。
我最好的尝试,到目前为止是使用UNION
,允许同时使用by_user
和by_group
指标,但可能会挣扎后排序:
SELECT SQL_NO_CACHE
a.*, user.nickname
FROM (
(SELECT resource.* FROM resource WHERE user_id = '000000-0000-0000-0000-000000000000')
UNION
(SELECT resource.* FROM resource WHERE access_type = 3)
UNION
(SELECT resource.* FROM resource
INNER JOIN user_group ON (access_type = 2 AND user_group.group_id = resource.group_id)
WHERE user_group.user_id = '000000-0000-0000-0000-000000000000'
AND user_group.type IN (1, 2, 3)
)
) a
LEFT JOIN user ON (user.id = a.user_id)
ORDER BY created DESC;
的EXPLAIN
输出告诉我,它使用索引都SELECT
s并在UNION
的行上以type: ALL/Using filesort
结束ORDER BY
。但是,如果我想排序和限制,我猜可能会变得很沉重,因为在元组上没有索引。
另一种可能是为Groups
的User
子查询一个简单的查询是:
SELECT SQL_NO_CACHE
resource.*, user.nickname
FROM resource
LEFT JOIN user ON (user.id = resource.user_id)
WHERE user_id = '000000-0000-0000-0000-000000000000'
OR access_type = 3
OR (access_type = 2 AND group_id IN
(SELECT group_id FROM user_group USE INDEX (`user_group`)
WHERE user_id = '000000-0000-0000-0000-000000000000' AND type IN (1, 2, 3)
)
)
ORDER BY created DESC;
但这里的EXPLAIN
告诉我,它不会使用索引,并在Resource
执行选择type: ALL/Using where; using filesort
表,女巫是我想要避免的。如果我尝试FORCE INDEX(by_user, by_group)
,则首先合并两个索引type: index_merge/Using sort_union(by_user,by_group); Using where; Using filesort
,这可能也很昂贵。
有什么更好的想法吗?这个请求可能会频繁地叫......
感谢您花时间阅读和回答。当我开始工作时,我会运行一些测试。 – 2010-01-04 17:13:33