对我的数据库设计的反馈(多租户)。

问题描述 投票:0回答:1

这个SaaS工具的想法是有动态的表,有动态的自定义字段和不同类型的值,我们想用 "force.comsalesforce.com "的例子,但似乎太复杂了,要维护前进,还要创建一些报表,有一个巨大的抽象层次,所以我们想到了简单的想法,但我们必须确定这是一个挺好的方法。

这就是我们今天的架构(分几步)。

  1. 每个租户在集群上有自己独立的数据库(Postgres 12)。
  2. TABLE表,用来保存所有这些表作为参考,这个实体与META表有ManyToOne关系,与DATA表有OneToMany关系。
  3. META表用于元数据的配置,与FIELDS有OneToMany关系(其中有字段的名称以及字段的类型,比如。TEXT/INTEGER/BOOLEAN/DATETIME 等字段的名称以及字段的类型和属性值--作为字符串,只能作为引用)。)
  4. DATA表与TABLES和DATA表有ManyToOne关系。50 character varying 等名称的列。attribute1...50 这些列的名字都是NULL的。

今天的例子流程。

  1. 当用户想打开一个TABLE DATA,例如 "CARS",我们加载了META表的所有FIELDS(以获得本次查询的字段)。用户指定他要查询的。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' 我们使用 CAST() 的功能 SQL 比如 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查询语言)的抽象语言,这样就可以管理简单的WHERE语句(less,equal,null等)。
  • 交易锁定,因为我们允许批量上传CSV到系统中。DATA_X 所以一旦他们要加载例如1GB的数据,就会把表锁住,让其他系统访问DATA表。
  • 保留多个NULL列,这可能会影响空间(目前我们还没有那么害怕,因为在创建TABLE的时候,客户可以决定他想要多少列,所以基于这一点,我们将这个TABLE分配给一个硬编码的实体。DATA_5, DATA_10, DATA_15, DATA_20, DATA_30, DATA_50其中数字对应于属性列的限制,而这些实体是不同的,我们也支持迁移选项,如果他们决定从5个属性切换到10个属性等。

我们正处于超级早期阶段,所以我们可以在扩展之前做这些事情,因为我们知道这是一个很好的解决方案。很可能 并不是最好的方法,但我们保留了它来为小客户运行项目,目前运行得很好。

我们也曾想过用JSONB对象,但那不是我们的选择,因为我们想保持数据的简单性。

你对这个解决方案有什么看法(仅供参考,DATA有两个表的PRIMARY键--(ID,TABLEID)和内建的CreatedAt列,这在大多数查询中都会用到,所以最多会有3个索引)?

如果它看起来不好,你会推荐什么作为这个解决方案的替代方案,基于我分享的细节(基本上是无模式的RDBMS)?

postgresql database-design rdbms multi-tenant saas
1个回答
1
投票

IMHO,我预计当你想加入表,也使用铸造等问题。

我们曾按照下面的方法,这将是对你的帮助

我们有一个表,叫做 Cars 也有几张表,如 CarsMeta, CarsExtension 列。基本的 Cars 表将有所有租户的通用字段。此外,我们将有 CarsMeta 表指出,你可以有哪些类型的列,用于扩展 Cars 实体。在 CarsExtension 表,你会有这样的列 StringCol1...5, IntCol1....5, LongCol1...10

这样一来,你就可以轻松地过滤数据也喜欢。

  • 如果你在基表上有一个过滤器,执行搜索,如果找到结果,将id与 CarsExtension 表,以获得该实体的扩展行列表。
  • 如果过滤器是在扩展字段上,在扩展表上进行搜索,并与基本实体id匹配。
  • 因为我们的扩展表的组织结构如下所示

    id - UniqueId

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

    StringCol1 - string,

    ...

    IntCol1 - int,...

在这种情况下,将很容易为实体做一个连接,然后获得数据和扩展字段。

如果从不同的表中推断出表的元数据和数据,那么在长时间和大量数据的情况下,维护这些元数据和数据将是一项困难的任务。

HTH

© www.soinside.com 2019 - 2024. All rights reserved.