【问题标题】:Can this query be rewritten without UNION, and is it scaleable?这个查询可以在没有 ONION 的情况下重写,它是否可扩展?
【发布时间】:2012-12-13 03:49:00
【问题描述】:

我有几张桌子:

  • product-表中,我有一个产品列表。
  • user-表中,我有一个用户列表。
  • group-表中,我有用户组。
  • group_member 表中,我已链接groupmember(多对多)
  • user_product 表中,我已链接userproduct(多对多)
  • group_product 表中,我已链接groupproduct(多对多)

所以一个用户可以有很多产品,一个产品可以有很多用户。一个用户可以是多个组的成员,一个组可以有多个成员。一个组可以有很多产品,一个产品可以有很多组。换句话说,一个产品可以同时拥有组和用户。

我想问数据库的是:“列出给定user 可以访问的所有产品,或者通过user_product-表中的直接关系,或者通过用户所属的组.我要产品名和用户名。”

这是我想出的查询:

# 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 查询更好/可能?如果有 100 000 个用户、10 000 个组和 100 个产品,这会是一个快速查询吗? 这是一个好的数据库设计,还是以其他方式存储此逻辑更好?

(这是我的第一个更复杂的查询。)

【问题讨论】:

  • 是的:您可以将 {{group_productgroupgroup_member} + {user_product}} 放在中间的一个较小的联合中,或者避免联合并使用两个左连接 +合并,(或 carthesian 产品 * EXISTS {3-table join} OR EXISTS {user_product})。这并不难,它只是工作。 CTE 也可能有帮助,但 mysql 没有 CTE
  • EXPLAIN 告诉您有关此查询的什么信息?
  • @wildplasser 哇,这会更可扩展吗?如果是这样,请添加更详细的答案! :D 我的意思是,如果这不仅仅是可能的事情。我不是在消除 UNION 之后,我在追求性能。
  • @JanDvorak 我对大型数据库确实有点陌生,我还没有使用过 EXPLAIN,但我会尝试并报告。
  • @JanDvorak EXPLAIN 给了我 6 行信息。我想你对rows 以及它在哪里使用索引感兴趣。我已经优化了索引。但是,出于某种原因,rows 始终为 1。我之前没有使用过EXPLAIN,所以我没有使用它的经验。截至目前,有两个用户,两个组,六个产品。所以现在在 1.2 毫秒内运行......

标签: mysql sql database-design join


【解决方案1】:

您的查询为您的数据模型提供了正确的方法。数据模型的“正确性”实际上取决于更改的数量和频率——无论何时将用户添加到组或从组中删除,您都可以选择始终存储明确的用户-产品关系。这是一种非规范化策略,将开销从查询转移到更新 - 通常最好不要考虑这些移动,除非性能经过测试并且存在缺陷。

一个非常小的优化可能是避免在联合之后加入用户和产品。目前您只选择产品名称和用户名,但如果您选择许多列,排序/区分将涉及比严格必要的更多工作,因此类似于:-

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-11
    • 2013-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-23
    相关资源
    最近更新 更多