Dynamic , Static or Seperate Schema Design (Convert No-SQL to ORDBMS)

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云数据库 MongoDB,通用型 2核4GB
简介:
昨天和我们单位的一位开发人员聊天,关于一个项目,原来程序后端用的数据库是mongoDB sharding,准备迁到PostgreSQL。
迁移过来的话涉及到从非结构化转结构化的过程。
首先说说原来mongoDB里面存储的内容 : 
document1: {用户标识(带字符串数字),用户的消费情况(如业务a,消费多少,业务b消费多少,业务z消费多少)} 
document2: {用户标识(带字符串数字),用户的消费情况(如业务d,消费多少,业务f消费多少)} 
documentn: {....} 
程序数据库的主要操作类型:
1. 用户以前消费过的业务的值得变更,修改“用户的消费情况"这个key的值。
2. 用户以前没有消费过的业务的新增,修改“用户的消费情况"这个key的值。
3. 查询用户的消费情况(单业务,多业务,全业务,总计等)。

  转换到PostgreSQL的时候使用用户的标识,在应用层转换为数字,并对这个数字取2的N次方的模。也就是说把用户的数据分割成了2的N次方份。
  【注】在这里设计mongoDB sharding和PostgreSQL分区的时候都没有考虑跨库事务和全局事务状态一致。(主要依赖几台服务器的时间同步来做时间点一致的恢复)

大体的方向已经确定了(表分割,分库)。
如4台服务器,将2的N次方个表分布到这4台服务器上。(STANDBY和高可用的情况不在本文讨论)

在确定PostgreSQL里面的表结构的时候,面临一个选择题:
  1. 一张表,字段如下 (Static Schema)
userid , appid1_value , appid2_value , appid3_value , appid4_value ... appidn_value , count_value
  2. 一张表,字段如下 (Dynamic Schema)
userid , json_text (内容格式appid1_value , appid2_value , appid3_value , appid4_value ... appidn_value , count_value)
  3. 每个APPID各一张表,COUNT一张表。表字段如下 (Seperate Schema)
userid , appid_value
userid , count_value

针对在mongoDB里面的三种常用数据库操作,这里的三种设计结构各有优缺点:
1. 用户以前消费过的业务的值得变更,修改“用户的消费情况"这个key的值。
如使用Static Schema,update tbl_static set appidn_value=$1,count_value=$2 where userid=$3; 
优点,count_value和appidn_value在一个事务里面操作,并且一个USERID同时只允许一个更新SQL,原子性得以保证。
缺点,新增APPID时需要变更表结构。某些用户可能成为热点,如同一时间同一个用户频繁提交不同的APPID更新请求(虽然手机上理论上这种情况很少见,但是可能存在攻击行为)。

如使用Dynamic Schema,update tbl_dynamic set json_text=$1 where userid=$2; 
优点,count_value和appidn_value在一个事务里面操作,并且一个USERID同时只允许一个更新SQL,原子性得以保证。
缺点,某些用户可能成为热点,如同一时间同一个用户频繁提交不同的APPID更新请求(虽然手机上理论上这种情况很少见,但是可能存在攻击行为)。

如使用Seperate Schema,begin; update tbl_sperate_appidn set appid_value=$1 where userid=$2;  update tbl_sperate_count set count_value=$1 where userid=$2; 
优点,与上面不同的是如果同一时间同一个用户频繁提交不同的APPID更新请求,这种设计不存在用户热点,但是频繁提交同一个APPID的更新请求还是和前面一样。
缺点,新增APPID时需要增加表。count_value和appidn_value在一个事务里面操作,如果同一时间同一个用户ID还在操作另一个APPID时,可能存在COUNT表的锁等待事件增加。

2. 用户以前没有消费过的业务的新增,修改“用户的消费情况"这个key的值。
如使用Static Schema,update tbl_static set appidn_value=$1,count_value=$2 where userid=$3; 如果返回记录不存在则插入;(乐观考虑)
优点,count_value和appidn_value在一个事务里面操作,并且一个USERID同时只允许一个更新SQL,原子性得以保证。
缺点,新增APPID时需要变更表结构。某些用户可能成为热点,如同一时间同一个用户频繁提交不同的APPID更新请求(虽然手机上理论上这种情况很少见,但是可能存在攻击行为)。

如使用Dynamic Schema,update tbl_dynamic set json_text=$1 where userid=$2; 如果返回记录不存在则插入;(乐观考虑)
优点,count_value和appidn_value在一个事务里面操作,并且一个USERID同时只允许一个更新SQL,原子性得以保证。
缺点,某些用户可能成为热点,如同一时间同一个用户频繁提交不同的APPID更新请求(虽然手机上理论上这种情况很少见,但是可能存在攻击行为)。

如使用Seperate Schema,begin; update tbl_sperate_appidn set appid_value=$1 where userid=$2;  update tbl_sperate_count set count_value=$1 where userid=$2; (悲观考虑,因为COUNT和APPID表在一个事务里面,这里建议考虑悲观情况,以免经常性的事务回滚)(首先要判断count里面有没有USERID,另外还要判断APPID表里面有没有USERID,最后是插入APPID表的动作以及插入或更新COUNT表的动作)
优点,与上面不同的是如果同一时间同一个用户频繁提交不同的APPID更新请求,这种设计不存在用户热点,但是频繁提交同一个APPID的更新请求还是和前面一样。
缺点,新增APPID时需要增加表。count_value和appidn_value在一个事务里面操作,如果同一时间同一个用户ID还在操作另一个APPID时,可能存在COUNT表的锁等待事件增加。

3. 查询用户的消费情况(单业务,多业务,全业务,总计等)。
如使用Static Schema,select appidn_value,...,count_value from  tbl_static where userid=$1;
优点,单业务,多业务,全业务,总计,查询耗费的物理IO一致。
缺点,不能把表分布到不同的物理存储。不能做字段压缩。

如使用Dynamic Schema,select appidn_value,...,count_value from  tbl_dynamic where userid=$1;
优点,单业务,多业务,全业务,总计,查询耗费的物理IO一致。可以做字段压缩。
缺点,每次查询都需要get整个text,可能造成网卡流量的上升(一般流量不存在问题)。不能把表分布到不同的物理存储。

如使用Seperate Schema,多业务查询和全业务查询需要考虑事务隔离度,更加复杂。
优点,可以把表分布到不同的物理存储。
缺点,多业务或全业务查询时需要更多的物理IO请求。

综合考虑后,选择了Dynamic Schema设计。
1. 同一时间同一个用户频繁提交APPID value更新请求。程序设计了黑名单来防止异常用户攻击。
2. 因为可以做字段压缩,三种结构中Dynamic Schema耗费的物理空间最小。
3. 每次查询都需要get整个text,可能造成网卡流量的上升,现在网卡速度都还不错,一般流量不存在问题。
4. 使用上更加灵活,因为TEXT的内容完全由程序定义,用户增加APPID的信息不需要变更结构。
相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。   相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
存储 SQL
sql server 存储过程传递表名参数及Dynamic SQL
sql server 存储过程传递表名参数及Dynamic SQL
sql server 存储过程传递表名参数及Dynamic SQL
|
SQL Java 数据库连接
Data Access 之 MyBatis(四) - Dynamic SQL(下)
Data Access 之 MyBatis(四) - Dynamic SQL
Data Access 之 MyBatis(四) - Dynamic SQL(下)
|
SQL Java 数据库连接
Data Access 之 MyBatis(四) - Dynamic SQL(上)
Data Access 之 MyBatis(四) - Dynamic SQL
Data Access 之 MyBatis(四) - Dynamic SQL(上)
使用CL_RS_WHERE创建dynamic SQL statement
使用CL_RS_WHERE创建dynamic SQL statement
使用CL_RS_WHERE创建dynamic SQL statement
One order search dynamic sql statement生成位置
One order search dynamic sql statement生成位置
One order search dynamic sql statement生成位置
|
SQL Java 数据库连接
Can I use MyBatis to generate Dynamic SQL without executing it?
Although MyBatis was designed to execute the query after it builds it, you can make use of it's configuration and a little bit of "inside knowledge" to get to what you need.
1309 0
|
SQL 大数据 API
Flink Table/SQL API 规划 —— Dynamic Table
动态表直观上看是一个类似于数据库中的`Materialized View`概念。动态表随着时间改变;类似静态的batch table一样可以用标准SQL进行查询然后一个新的动态表;可以和流无损地互相转换(对偶的)。
10215 0