【问题标题】:SaaS- Tenant Specific Lookup Data in Shared DatabaseSaaS - 共享数据库中的租户特定查找数据
【发布时间】:2012-10-06 08:32:09
【问题描述】:

我正在开发基于多租户 SaaS 的应用程序,并使用共享数据库在 TenantId 列的帮助下存储所有租户记录。

现在的问题是我有一些需要为所有租户共享的查找记录列表。例如游戏列表。

游戏桌

Id
GameName

还有另一个表用于仅存储特定于租户的记录

租户游戏

Id
TenantId
GameName  

基本需求是我想在加入另一个事务表(如 UserGames)时同时使用两个表数据并获取必要的详细信息(Game_Name)。我怎样才能通过这种设计实现这一目标? 这里的 Game_Name 可以从 Games Shared 表或 TenantSpecificGames 表中引用

是否有任何其他数据库设计允许我将公共主数据和租户主数据与 JOIN 混合在一起?

基本要求是保留通用数据并允许租户在他们想要添加任何新项目时进行自定义。

【问题讨论】:

  • UserGames 表是什么样的?在 TenantGames 中使用 GameID 而不是 GameName,它是 GamesTable 的 id 字段。

标签: database database-design saas multi-tenant


【解决方案1】:

这是我将使用的设计。

游戏

Id
GameName
IsTenantSpecific
SomeGameSpecificColumn

租户游戏

GameId
TenantId
SomeTenantSpecificColumn
AnotherTenantSpecificColumn

然后您可以在 Join 中查询该表:

...
FROM
    Games
    INNER JOIN UserGames ON
        UserGames.GameId = Games.Id
    LEFT JOIN TenantGames ON
        TenantGames.GameId = Games.Id
WHERE
    TenantGames.TenantId = @tenantId OR
    (
        TenantGames.TenantId IS NULL AND
        IsTenantSpecific = 0
    )

游戏特定字段可以放在游戏表中。租户特定字段可以添加到 TenantGames 表中,如果不是特定于租户的自定义,这些字段将为 NULL。

【讨论】:

  • 对两个查询进行 UNION 可能会更快。
【解决方案2】:

我们有一个基于 saas 的数据库,我们将常用数据和租户数据保存在同一个表中。

概念

GamesTable

    Id NOT NULL
    TenantId NULL
    GameName NOT NULL
    Add a unique key for TenantId and GameName
  • 如果 TenantId 为 NULL,你就知道它是公共数据
  • 如果 TenantId 不为 NULL,则您知道它属于特定租户以及确切的租户。

“是否有任何其他数据库设计可以让我混合两种常见的 JOIN主数据和租户主数据?”

是的

SELECT *
  FROM GamesTable where TenantId = 'your tenant id'
  UNION
SELECT *
  FROM GamesTable where TenantId IS NULL  -- common 

【讨论】:

  • 如果两个租户在 Games 表中添加相同的游戏会怎样?重复记录 :(
  • 你试过了吗?您永远不会让两个租户与这样的查询混淆。 WHERE GameName NOT IN (SELECT * FROM GamesTable where TenantId = 'your tenant id') 如果要过滤租户已覆盖的主记录。
【解决方案3】:

这是“多对多”的经典示例。

Table: Games
------------
GameID
GameName
IsMasterGame


TennantGames
------------------
GameID
TennantID

Tennants
------------
TennantID
...

要获取给定租户的游戏,您可以运行如下查询:

select *
from   Games
where isMasterGame = true
union
select * 
from Games g, 
TennantGames tg
where g.GameID = tg.GameID
and   isMasterGame = false
and   tg.TennantID = $currentTennant

(对过时的连接语法表示歉意)

工会允许您提出两个问题:哪些游戏适用于所有人 (isMasterGame = true),其次哪些游戏适用于当前租户 (tg.TennantID = $currentTennant)。从逻辑上讲,租户游戏也不可能是大师游戏。

【讨论】:

  • 好的。我们是否可以有一个包含所有主游戏和 TenantGames 的桌面游戏,其中包含租户指定的游戏并合并两个?
  • 但是我们如何在交易明细表中引用/区分它呢?例如 UserPlayedGamesTable (Id, GameId references?) 。如何使用主表和自定义表加入以显示游戏名称?
  • 啊。好吧,您可能想要更新问题以将此作为要求包含在内...我将发布对此的建议答案。
【解决方案4】:

您可以合并表,将 TenantId 保留为 NULL 用于您不希望特定于租户的记录。

游戏

Id
TenantId
GameName

您可以在 Join 中查询该表:

...
FROM
    Games
    INNER JOIN UserGames ON
        UserGames.GameId = Games.Id

WHERE
    Games.TenantId = @tenantId OR
    Games.TenantId IS NULL

这将为您省去确保 Id 在表之间唯一的麻烦,除非您对 Id 使用 UNIQUEIDENTIFIER。

【讨论】:

  • 但是如果两个不同的租户想要相同的游戏会发生什么?示例租户 D、E 只想要板球。我是否需要添加 2 个具有两个不同租户 ID 的 Cricket 行?但在这里我觉得我们违反了规范化政策。
  • 我一定误解了要求。请参阅我的另一个答案。 :-)
猜你喜欢
  • 1970-01-01
  • 2012-09-24
  • 2021-07-10
  • 2014-03-21
  • 2018-01-31
  • 2014-07-15
  • 2011-10-06
  • 1970-01-01
  • 2012-12-14
相关资源
最近更新 更多