很多用户有很多桌子吗?

时间:2010-05-17 23:03:48

标签: asp.net sql database-design

我有一个Web应用程序,在许多方面可以被认为是一个多租户环境。我的意思是,应用程序的每个用户都有自己的“自定义”环境,这些用户之间绝对没有交互。

到目前为止,我已将Web应用程序构建为“单用户”环境。换句话说,我实际上没有做任何事情来支持多用户,但只是从应用程序中获得了我想要的功能。这是我的问题......构建多用户环境的最佳方法是什么:

  1. 所有用户都指向相同的“核心”后端。换句话说,我构建了通过适当的SQL查询来分离用户的逻辑(例如,select * from table where user ='123'和attribute ='456')。
  2. 每个用户都指向一个唯一的表空间,该表空间在加入系统时单独构建。在这种情况下,我只需为每个用户生成所有相关的SQL表,并为用户添加某种后缀。 (例如,现在查询看起来像'select * from table_ where attribute ='456')。
  3. 简而言之,“select * from table where USER =”和“select * from table_USER”之间存在差异。

5 个答案:

答案 0 :(得分:4)

动态创建表非常脏并且令人困惑。此外,如果你有很多用户,如果你有大量的表,那将是一个完整的混乱 - 特别是如果你需要在n个表而不是单个表中更改某些东西。

- >使用一个表并添加一些 user_id 列。使用适当的索引,这将比单独的表快或甚至更快。

答案 1 :(得分:2)

第一种选择更好。

一般情况下,表格应包含规范化数据,不应复制同一个表格。

第一个选项也更安全,因为您不需要授予创建或删除真实表到程序的能力

答案 2 :(得分:1)

我会说你的选择取决于。你真的有三个选择:

一个数据库来统治它们......(您的选择1)

当然,添加TenantId列可以更轻松地添加新租户(用户),但有一些缺点:

  1. 您必须小心确保每个查询都针对TenantId进行过滤。很容易在正确的地方意外忘记TenantId并返回其他租户的数据。
  2. 所有顶级父表都必须包含TenantId。它不仅仅是您的主要数据,还包括所有特定于租户的父数据。
  3. 租户不能在不同时间使用不同的架构版本。例如,假设您在应用程序的1.1版中进行了一些数据架构更改。如果所有租户都在同一个数据库中,则无论您是否需要,都必须同时更新每个租户。此外,如果您使用单个数据库,则几乎不得不使用单个站点,以确保站点和架构保持同步。例如,如果您执行此操作,则无法向某人收取升级费用以获取新功能。这些功能必须构建为插件,而不是版本特定的更新,这可能不是一件坏事,但必须从一开始就做出有意识的决定。
  4. 如果租户的数据希望拥有其数据的副本或希望托管他们自己的数据,或者您希望将他们移动到另一个数据库服务器,那么分离租户的数据可能是件苦差事。由于所有资源都是共享的,因此您可能会遇到一个租户通过报告或流量咀嚼资源的情况,这样您就可以将它们移动到自己的数据库服务器上(并将这些优势向上销售)。此外,我遇到了租户想要他们可以自己下载的数据副本的情况。如果所有数据都在一个数据库中,这可能是一件苦差事。
  5. 如果您打算向公司客户销售产品,那么我就不会走这条路了。但是,如果您计划将成千上万的最终用户添加为不需要向他们提供数据的租户,那么使用单个数据库可能是正确的方法。

    按模式细分租户(例如Tenant1.Table1,Tenant1.Table2 ... Tenant2.Table1,Tenant2.Table2 ......)(我相信您的选择2)

    IMO,这是一个简单使用单独数据库的难度版本。它的优点是维护一个数据库更容易,但除此之外还有与使用单独数据库相同的问题。

    每个数据库的细分租户

    对于企业客户,我发现最终这是最简单的。它消除了租户看到错误数据的可能性(除非连接字符串错误)。它允许公司托管他们自己的系统。如果每个租户有不同的虚拟应用程序,它允许租户使用不同的版本。它可以轻松进行资源分配,备份和恢复。它只是(但不是微不足道)的缺点是设置的时间成本(以及财务成本)。获得新客户端时添加数据库可能会很麻烦。从技术上讲,它可以自动化,但仍然很痛苦。

    所以,最终它取决于您的目标客户。如果他们是标准用户,那么我会选择“一个数据库来统治他们”的方法,并确保您进行大量的代码审查和自动化测试。如果他们是企业客户,特别是大型企业客户,那么我会考虑每个租户单独的数据库。

答案 3 :(得分:0)

每个租户的单独表格的唯一方法是,如果每个租户都有一个单独的数据库,在这种情况下,表格仍然具有相同的名称。

否则,为每个实体使用一个表,并按租户ID过滤它们。

答案 4 :(得分:0)

如果您使用的是SQL Server,我建议对所有租户使用单个表,不要将基表访问应用程序正在使用的任何登录,并限制对内联表值函数的访问。这些就像参数化视图一样,意味着没有人可以访问这些视图,只能在一次调用中为多个租户检索一组(因此不会偶然加入其他人的产品目录):

CREATE TABLE [dbo].[mt](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [TenantID] [int] NOT NULL,
    [BusinessKey] [varchar](50) NOT NULL,
 CONSTRAINT [PK_mt] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
),
 CONSTRAINT [IX_mt] UNIQUE NONCLUSTERED 
(
    [TenantID] ASC,
    [BusinessKey] ASC
))

CREATE FUNCTION f_mt ( @TenantID AS INT )
RETURNS TABLE
AS
RETURN
    ( SELECT    *
      FROM      mt
      WHERE     TenantID = @TenantID
    )

如果您将TenantID存储在连接中的某个位置(使用CONTEXT_INFO()),那么也可以使用简单的视图来包装它:

CREATE VIEW vw_mt
AS
    SELECT *
    FROM f_mt(CONTEXT_INFO())

这一切都取决于你想要多少抽象。

相关问题