正如 Martin Smith 和 Mikael Eriksson 所提到的,将其作为实体的属性是一种非常简洁和直接的方法。纯粹就数据表示而言,这给人一种非常好的感觉。
但是,我也会考虑您可能对数据进行的查询。例如,根据您的描述,您的查询似乎最有可能从单个用户开始,找到他们所属的组,然后找到与他们关联的实体。可能是这样的...
SELECT DISTINCT -- If both user and entity relate to multiple groups, de-dupe them
entity.*
FROM
user
INNER JOIN
user_link_group
ON user.id = user_link_group.user_id
INNER JOIN
group_link_entity
ON group_link_entity.group_id = user_link_group.group_id
INNER JOIN
entity
ON entity.id = group_link_entity.entity_id
WHERE
user.id = @user_id
如果您要使用这种格式,以及实体表中的属性的想法,您将需要一些不那么优雅的东西,我认为以下 UNION 方法可能是最有效的......
<ORIGINAL QUERY>
UNION -- Not UNION ALL, as the next query may duplicate results from above
SELECT
entity.*
FROM
entity
WHERE
EXISTS (SELECT * FROM user_link_group WHERE user_id = @user_id)
AND isVisibleToAllGroups != 0
-- NOTE: This also implies the need for an additional index on [isVisibleToAllGroups]
而不是在“我可以看到什么实体”查询中创建极端情况,而是在链接表的维护中创建极端情况......
- 创建一个全球组
- 如果一个实体对所有组可见,则将它们映射到 GLOBAL 组
- 如果将用户添加到组,请确保他们也链接到 GLOBAL 组
- 如果用户从所有组中删除,请确保他们也从 GLOBAL 组中删除
这样,原始的简单查询无需修改即可工作。这意味着不需要 UNION,它有排序和重复数据删除的开销,也不需要 isVisibleToAllGroups 上的 INDEX。相反,开销转移到维护用户链接到哪些组;而是一次性开销。
这假设“我可以看到哪些实体”这个问题比更改组更常见。它还添加了由 DATA 而不是由 SCHEMA 定义的行为,这需要良好的文档和理解。因此,我确实将其视为一种强大的优化类型,但我也将其视为一种需要在数据库设计中考虑的交易和平衡类型的妥协。