我有几张桌子:
product
- 表中,我有一个产品清单。user
- 表中,我有一个用户列表。group
- 表中,我有一组用户。group_member
- 表中,我已关联group
和member
(多对多)user_product
- 表中,我已关联user
和product
(多对多)group_product
- 表中,我已关联group
和product
(多对多)因此,用户可以拥有许多产品,产品可能拥有许多用户。用户可以是许多组的成员,组可以有许多成员。一个组可以有很多产品,一个产品可以有很多组。换句话说,产品可以同时拥有组和用户。
我想问的数据库是:“列出给定user
有权访问的所有产品,通过user_product
- 表中的直接关系,或通过user是其成员。我想要产品的名称和用户的名称。“
这是我提出的查询:
# First get all the products the user has access to via a group.
SELECT product.name,
user.first_name
FROM product
INNER JOIN group_product
ON group_product.product_id = product.product_id
INNER JOIN group
ON group.group_id = group_product.group_id
INNER JOIN group_member
ON group_member.group_id = group.group_id
INNER JOIN user
ON user.user_id = group_member.user_id
WHERE user.user_id = 1
UNION
# Now get all the products via direct access from user_product.
SELECT product.name,
user.first_name
FROM product
INNER JOIN user_product
ON user_product.product_id = product.product_id
INNER JOIN user
ON user.user_id = user_product.user_id
WHERE user.user_id = 1
这是一个很好的查询,还是更好/可能将其重写为仅JOIN查询?如果有10万用户,10 000个群组和100个产品,这会是一个快速查询吗? 这是一个很好的数据库设计,还是以另一种方式存储这个逻辑更好?
(这是我的第一个更复杂的查询。)
答案 0 :(得分:2)
您的查询对您的数据模型有正确的方法。数据模型的“正确性”实际上取决于数量和变化频率 - 您可以选择在用户添加到组或从组中删除时始终存储显式用户 - 产品关系。这是一种非规范化策略,将开销从查询转移到更新 - 通常最好不考虑这些移动,除非性能经过测试和不足。
非常小的优化可能是在联合之后避免加入用户和产品。目前,您只选择产品名称和用户first_name,但如果您选择了多个列,则排序/不同将涉及更多工作而非严格必要的工作,如下所示: -
select product.name, user.first_name
from
(
select
group_product.product_id
from
group_product
inner join group on group.group_id = group_product.group_id
inner join group_member on group_member.group_id = group.group_id
where group_member.user_id = 1
union
select product_id product.name,
from user_product
where user_product.user_id = 1
) as d
inner join product on product.product_id = d.product_id
inner join user on user.user_id = 1