【问题标题】:Feedback about my database design (multi tenancy)关于我的数据库设计的反馈(多租户)
【发布时间】:2020-08-13 00:21:00
【问题描述】:

SaaS 工具的想法是拥有具有不同类型的动态自定义字段和值的动态表,我们曾考虑使用“force.com/salesforce.com”示例,但似乎太复杂而无法继续前进,还制作了一些具有巨大抽象级别的报告来创建,因此我们提出了简单的想法,但我们必须确保这是一种不错的方法。

这就是我们今天拥有的架构(只需几个步骤)。

  1. 每个租户在集群上都有自己独立的数据库 (Postgres 12)。
  2. TABLE 表,用于将所有这些表作为参考,该实体与 META 表具有 ManyToOne 关系,与 DATA 表具有 OneToMany 关系。
  3. META 表用于元数据配置,与 FIELDS 具有 OneToMany 关系(具有字段名称以及字段类型,例如 TEXT/INTEGER/BOOLEAN/DATETIME 等和属性值 - 作为字符串,仅作为参考)。李>
  4. DATA 表与 TABLES 和 50 character varying 列具有 ManyToOne 关系,其名称如下:attribute1...50,它们可以为 NULL。

今天的示例流程:

  1. 当用户想要打开表数据时,例如“CARS”,我们加载包含所有字段的 META 表(以获取此查询的字段)。用户指定他要查询:Brand, Class, Year, Price 列。
  2. 我们正在通过逻辑检查 META>FIELDS 表中品牌、类别、年份和价格的参考,所以我们知道Brand = attribute2, Class = attribute 5, Year = attribute6 and Price = attribute7
  3. 我们将他的请求解析为查询,例如:SELECT [attr...2,5,6,7] FROM DATA,然后将结果显示给用户,如果用户决定对其进行一些过滤,则基于此数据,例如Year > 2017 AND Class = 'A' 我们使用SQLCAST() 功能,例如SELECT CAST(attribute6 AS int) AND attribute5 FROM DATA WHERE CAST(attribute6 AS int) > 2017 AND attribute5 = 'A';,那么我们实际上可以支持SQL 的大部分原理。

但是前进我们有点害怕:

  • 为更多租户管理这样的环境,同时我们将拥有更多表 (e.g. 50 per customer, with roughly 1-5 mil per TABLE (5mil 是我们允许的最大值,对于更大的数据,我们有 BigQuery) which is giving us 50-250 mil rows in single table DATA_X) 这可能会影响查询的性能,尤其是当我们提供可能性时使用一些抽象语言来管理简单的 WHERE 语句(less、equal、null 等),例如GET CARS [BRAND,CLASS,PRICE...] FILTER [EQ(CLASS,A),MT(YEAR,2017)] 开发为类似于 JQL(Jira 查询语言)。
  • 事务锁定,因为我们允许将 CSV 批量上传到DATA_X,所以一旦他们想要加载,例如1GB 的数据,它有点锁定表,以供其他系统访问 DATA 表。
  • 保留多个 NULL 列,这可能会稍微影响空间(现在我们并不像在创建 TABLE 时那样害怕,客户可以决定他想要多少列,因此我们将此 TABLE 分配给硬编码实体之一@ 987654335@,其中数字对应于属性列的限制,并且这些实体是不同的,如果他们决定从 5 个属性切换到 10 个属性等,我们也支持迁移选项。

我们处于超早期阶段,因此我们可以/应该在扩展之前做出这些,因为我们知道这很可能不是最好的方法,但我们保留它来运行项目目前运行良好的小客户。

我们也在考虑 JSONB 对象,但这不是选项,因为我们希望保持简单以获取数据。

您对此解决方案有何看法(仅供参考 DATA 具有 2 个表中的 PRIMARY 键 - (ID,TABLEID) 并内置列 CreatedAt 用于大多数查询,因此最多会有 3 个索引)?

如果看起来很糟糕,您会根据我分享的详细信息(基本上是无模式的 RDBMS)推荐什么作为此解决方案的替代方案?

【问题讨论】:

    标签: postgresql database-design rdbms multi-tenant saas


    【解决方案1】:

    恕我直言,我预计当您想加入表格并使用演员表等时会出现问题。

    我们已按照以下方法对您有所帮助

    我们有一个名为Cars 的表,还有几个表,如CarsMetaCarsExtension 列。底层Cars 表将包含所有租户的所有公共字段。此外,我们将让CarsMeta 表指出您可以拥有哪些类型的列来扩展Cars 实体。在CarsExtension 表中,您将拥有StringCol1...5, IntCol1....5, LongCol1...10 之类的列

    通过这种方式,您可以轻松过滤数据,例如,

    • 如果您对基表有过滤器,请执行搜索,如果找到结果,请将 ID 与 CarsExtension 表匹配以获取此实体的扩展行列表
    • 如果过滤器在扩展字段上,请在扩展表上进行搜索并与基本实体 ID 匹配。
    • 因为我们将按如下方式组织扩展表

      id - UniqueId

      entityid - uniqueid(指向实体的主键)

      StringCol1 - 字符串,

      ...

      IntCol1 - 整数, ...

    在这种情况下,很容易对实体进行连接,然后将数据与扩展字段一起获取。

    如果您的表元数据和数据是从单独的表中推断出来的,那么在很长一段时间内维护这些数据以及大量数据将是一项艰巨的任务。

    HTH

    【讨论】:

    • 感谢您的反馈,如果我理解正确,我们将有表格“汽车”,其中将包含一些常见数据,如高级汽车、普通汽车等。假设我们选择了“普通汽车”,所以我们模拟“Budget Cars”的 ID 并使用此 ID 对“CarsMeta”进行查找,我们将获得所有元数据,例如 Label-Value-ReferenceColumnName “Year - Integer - IntColumn5, Price - Numeric - NumericField10。然后我们可以获取汽车项目使用 CarsMeta 进行过滤,并仅获取与提供的文件管理器匹配的项目,因此我们从“CarsExtension”中获取结果并进行相应的解析。
    • 你测试的音量是多少?每个字段类型都有单独的表格,还是有大量的列名?想做类似的事情,但要加入更多的表,例如CarsValues_strings、CarsValues_integers、CarsValues_numerics、CarsValues_booleans 等,因此我们甚至可以根据许多其他表拆分表的大小。
    猜你喜欢
    • 1970-01-01
    • 2012-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-03
    • 1970-01-01
    • 2015-03-20
    • 2014-04-17
    相关资源
    最近更新 更多