【发布时间】:2020-08-13 00:21:00
【问题描述】:
SaaS 工具的想法是拥有具有不同类型的动态自定义字段和值的动态表,我们曾考虑使用“force.com/salesforce.com”示例,但似乎太复杂而无法继续前进,还制作了一些具有巨大抽象级别的报告来创建,因此我们提出了简单的想法,但我们必须确保这是一种不错的方法。
这就是我们今天拥有的架构(只需几个步骤)。
- 每个租户在集群上都有自己独立的数据库 (Postgres 12)。
- TABLE 表,用于将所有这些表作为参考,该实体与 META 表具有 ManyToOne 关系,与 DATA 表具有 OneToMany 关系。
- META 表用于元数据配置,与 FIELDS 具有 OneToMany 关系(具有字段名称以及字段类型,例如
TEXT/INTEGER/BOOLEAN/DATETIME等和属性值 - 作为字符串,仅作为参考)。李> - DATA 表与 TABLES 和
50 character varying列具有 ManyToOne 关系,其名称如下:attribute1...50,它们可以为 NULL。
今天的示例流程:
- 当用户想要打开表数据时,例如“CARS”,我们加载包含所有字段的 META 表(以获取此查询的字段)。用户指定他要查询:
Brand, Class, Year, Price列。 - 我们正在通过逻辑检查 META>FIELDS 表中品牌、类别、年份和价格的参考,所以我们知道
Brand = attribute2, Class = attribute 5, Year = attribute6 and Price = attribute7。 - 我们将他的请求解析为查询,例如:
SELECT [attr...2,5,6,7] FROM DATA,然后将结果显示给用户,如果用户决定对其进行一些过滤,则基于此数据,例如Year > 2017 AND Class = 'A'我们使用SQL的CAST()功能,例如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