SCI论文(www.lunwensci.com)
摘 要:传统的关系型数据库在字段扩展方面一直存在争议,主要表现在流量大的情况下,更新过程中会出现负载过高等 风险。文章通过分析库、表、字段、主键、索引、行、列等数据库特性,提出一种新的数据库设计,以行转列方式动态添加字 段,实现数据库的字段扩展。
Analysis and Design of Row-to-column Method Based on Relational Database
LI Chunwei
(Armed Police Command Academy, Tianjin 300250)
【Abstract】: The traditional relational database has always been controversial in terms of field expansion, mainly in the case of large traffic, and there will be risks such as excessive load during the update process. By analyzing database characteristics such as database, table, field, primary key, index, row, column, etc., this paper proposes a new database design, which dynamically adds fields by row-to-column and realizes field expansion of the database.
【Key words】:database;relational;row;column;field;index;property;paradigm;middleware;aggregation
良好的数据库设计随着时间的推移可以呈现出巨大 的优势,使系统始终灵活清晰、易于扩展。但遗憾的是目 前大多数数据库都存在时间越久越难以维护的情况, 一旦 业务更新迭代,就必须添加新字段。如何降低字段扩展的 复杂度减少数据库负载压力就成为了数据库设计研究的重 点。本文借鉴一些非关系型数据库列式存储的特点,以行 转列方式 [1] 提出一种新的数据库设计,对其进行分析拆 解,实现在关系型数据库中不需要额外执行新的 DDL 就 可以添加新字段,从而应对各种灵活的业务场景。
1 数据库核心设计
1.1 初始数据表的设计
任何数据库都包含最基本的初始数据表。初始数据 表中的数据作为初始数据,粒度单一,是唯一存在且不 可变的值。以不可变唯一的值作为主键存储数据,可以 快速查找、关联属性 [2]。初始数据表设计的好坏决定了 整个系统未来的规划与扩展。在数据库传统设计模式 中,业务场景相对简单时反范式设计经常被使用,其原 因是数据量小,一张表就可以覆盖所有数据,简单清楚。但反范式数据库增加信息属性时只在一张表上增加 字段,系统不断迭代,表上的字段就越多。若字段之间 相似或产生歧义,会严重干扰后期维护人员的分析判断, 对业务扩展十分不便,还会降低聚集计算的查询速度。
此次数据库初始数据表的设计理念就是减少数据库 设计的复杂度,使得逻辑结构清晰化,不产生歧义。首 先初始数据必须包含主键 ID, 这个 ID 与数据库传统设 计中一样都是唯一的主键 ID,且是数字主键 ID。指定 唯一的数字主键 ID 对数据的增、删、改、查速度有明 显的提升。其次是名称,一个数字主键 ID 对应一个名 称。名称若出现重名现象,如人员管理系统中两个人都 叫张三,可以用张三1、张三2分别命名。因此成为初 始数据必须要满足两个特性,数字主键 ID 唯一,名称 唯一。除了数字主键 ID 和名称外,为了后续运维管理, 初始数据表中可以再增加一个描述字段,便于理解这条 数据代表的意义。
1.2 属性数据表的设计
通常一条完整的数据会有多个属性,有些属性之间也存在着继承关系,在初始数据表设计之后有必要进行 属性数据表的设计,将有继承关系的字段按 1 对 1 或 1 对多进行内部关联 [3]。属性数据表的结构与初始数据表 类似,除了数字主键 ID、名称和描述字段外,第 4 个 字段为父数字主键 ID 字段,形成属性之间的层级继承 关系。例如一本书既属于介绍地理的书又属于介绍太平 洋的书,地理和太平洋在逻辑上属于父子继承关系,如 果地理在属性数据表中数字主键 ID 为 10. 太平洋在属 性数据表中数字主键 ID 为 100.那太平洋这条数据的 父数字主键 ID 就为 10.这样太平洋属性和地理属性之 间的关系就确定了。同样的如果地理属性没有其父属 性,那其父数字主键 ID 就可以设置为 0.表示当前属 性为最高层级。这样做的好处是所有的具有继承关系的 属性可以只使用最子级的属性 ID 来关联,不需要父级 冗余的数据,并根据子级可以查到父级。
1.3 关联数据表的设计
传统的二范式数据库设计是将初始数据表与其外部 属性数据表结合进行数据的封装,以初始数据表中主数 据(数字主键 ID)进行关联。这种关联设计是将数据 库的主表关联,辅表以外键的形式进行内连接,一张主 表里存储相关属性的主键,多张表关联主表。其优点是主 表辅表关系明确,字段一目了然。然而当业务有新需求时, 字段越加越多,导致经常执行 DDL,在流量大的情况 下,会增加数据库负载压力,存在一定风险。因此关系 型数据库的传统设计更适用于小业务、少字段的场景。
关联数据表的设计借鉴了非关系型数据库特点,面 对多字段采用按列存储方式存储属性字段 [4]。我们将传 统设计转换一下, 假设在现有数据库中一行数据, 1000 个属性,一张表,每个属性都有其关联的外键 ID。此 次设计是先创建初始数据表,即以数字主键 ID、名称 作为主表,然后为 1000 个属性创建一张有继承关系的 属性数据表作为辅表,最后再创建一张关联表,将初始 数据表中的数字主键 ID 与属性数据表中的数字主键 id 做 1 对 1 或 1 对多的关联,这样关联表产生了 1000 条 数据, 3 个字段 :关联数据表数字主键 ID、初始数据表 数字主键 ID、属性数字表数字主键 ID。这种设计模式 下如果再新增 1000 个属性,不需要执行 DDL,只需要 在关联数据表中插入 1000 条新数据即可。
1.4 索引的设计
索引是提高数据库查询效率的必要功能之一,此次 设计中采用 Normal 类型索引。初始数据表为名称添加 索引,属性数据表中为父数字主键 id 添加索引,关联 数据表中除自增的数字主键 id 外,其余所有字段都添加索引 [5]。虽然这样会消耗一定的磁盘空间,但与不加 索引相比能够有效提高查询速度。在磁盘资源充沛的情 况下最好不要使用联合索引,除非该业务规则永远不会 改变且查询条件始终是自左相向右遵循联合索引的匹配 规则。
1.5 多级关联数据的设计
数据库的行转列方式如果在数据量庞大时可以对关 联数据表进行垂直分表。使关联数据表按分级处理,将 顶级字段关联数据放在顶级关联数据表中,一级字段关 联数据放在一级关联数据表中,以此类推按级别归类 [6]。 当数据量继续增加时还可以进行分库水平扩展,实现无 限动态扩容。对分级处理后的关联数据表创建表名,这 样数据库运维人员可以清楚分辨每张关联数据表的含 义,方便统筹系统。其次垂直分表的另一优势是分级处 理后,关联数据表中的数据不会太集中,查询速度变快。
2 数据库聚集计算的功能转移设计
关系型数据库查询可以采用聚集计算方式。例如查询 某个图书系统中有多少本“地理”书,假设地理在属性数 据表中数字主键 id 为 10.这种条件查询在传统数据库中 只需要一条语句就可以完成 :select count(*) from book_ store where category_id=10 group by book_id。而新设 计中的行转列关联数据表在聚集计算的使用上有比较多 的限制,例如 SUM 等计算需要先将多个属性封装成一 条属性也就是列再转回行,然后再进行聚集计算,这样 与传统数据库设计相比查询效率反而更慢了。为了弥补 这一缺陷,可以采取使用中间件计算的形式,将统计计 算的重心由数据库转移到应用上,从而实现聚集计算功 能的转移,使数据库只专注于处理关联索引的数据,以 保证查询效率。针对数据库的中间件层出不穷,其最重 要的功能就是为了减少数据库的计算压力。传统的研发 环境 Java、 .net、GoLang、Python 都可以实现针对 范围数据的聚集计算。
2.1 常用聚集计算中间件的实现
聚集计算中间件的实现是结合初始数据表、属性数 据表、关联数据表的特点,先利用表索引速度快的优势 将条件数据查询出来,随后进行数据封装,最后再利用 逻辑实现的聚集函数功能完成计算 [7]。
常用的 COUNT、SUM、AVG、MAX、MIN 聚集 计算, 是利用 Map 数据结构先对需要分组的属性进行 分组,再按 Key 进行计数统计,最后关联展示字段完 成查询。以 COUNT 聚集计算为例,以下伪代码实现双 字段查询功能 :
/**
* count 聚集计算的伪代码实现
* @param selectAttrId 需要展示的属性 id
* @param groupByAttrId 需要分组的属性 id
* @param originIdList 初始数据表数字主键集合
* @return 返回聚集计算结果
*/public Map countGroupBy(Long sid, Long gid, List oList) {List originList = dao.selectOriginList ById(oList);List relationList = dao.selectRelatio nAttrListById(oList);// 查出条件相关的所有数据封装成原始数据集合List bookList = service.packageBook (originList, relationList);return countGroupBy(bookList, sid, gid);// count 聚集计算}public Map countGroupBy(List list, Long sid, Long gid) {Map countMap = new Linked HashMap<>();Map selectMap = new Linked HashMap<>();for (Book book: list) {String attrValue = book.attrMap.get(gid);if (countMap.containsKey(attrValue)) {countMap.put(attrValue, countMap.get(attr Value) + 1);} else {countMap.put(attrValue, 1L);}selectMap.put(attrValue, book.attrMap.get (sid));}Map resultMap = new Linked HashMap<>();for (Map.Entry entry: countMap. entrySet())resultMap.put(selectMap.get(entry.getKey()), entry.getValue());}return resultMap;}
2.2 其他聚集计算中间件的实现
除上述常用的聚集计算之外,特定的 WHERE 条 件查询需要在计算前进行过滤,将数据源先进行封装, 若数据量巨大可以分批次封装,再参照常用的聚集计算 方法设计入参和出参,这样更加方便聚集计算的使用。
HAVING 条件需要在聚集计算过程中过滤,逻辑 的实现尽量选择时间复杂度高的算法,充分利用 CPU 和多线程资源,最后结合业务场景再次调整聚集计算的 功能后就可以完美的支撑这种动态行转列的数据库设 计,无论是效率上还是扩展上都能更上一层楼。
3 结语
关系型数据库性能稳定优越的特点结合这种行转列 的设计方式可以覆盖业界大多数应用场景,不过是否采 用这种设计还要结合具体实际去看。如果业务场景确实 非常清晰,不需要扩展或者扩展成本非常低,使用传统 的数据库设计更加合适 ;如果业务场景灵活且扩展性 强,或者不同的业务场景之间存在共性,则更适用本文 提出的行转列数据库设计方式。
行转列的设计是吸取和借鉴关系型数据库设计和非 关系型数据库设计优缺点演化而成,未来随着各种新的 应用场景不断问世,软、硬件的不断优化升级,更多的 数据库设计方案也将会向更贴近业务场景去演化和完善。
参考文献
[1] 张华东,邵秀丽,吴军,等.SQL Server数据库到HBase数据 库的模式转换和数据迁移研究[J].智能计算机与应用,2016.6 (5):24-30+34.
[2] 吴齐跃.基于列存储的大规模并行数据库应用技术[J].中国 管理信息化,2016.19(11):177-180.
[3] 刘岩松,李菲,陈萍.基于MySQL的飞机维修管理系统的设计 [J].电脑知识与技术,2022.18(8):103-105.
[4] 杨淙钧,艾中良,刘忠麟,等.基于多级列式索引的海量数据高 效查询设计[J].软件,2016.37(3):79-83.
[5] 王一竹.基于MySQL的图书馆信息管理系统设计[J].电脑编 程技巧与维护,2022(1):93-95+116.
[6] 安沈昊,于荣欢.基于MySQL的天地一体化网络结构数据库 构建[J].兵工自动化,2021.40(12):66-70.
[7] 杨超,梁波,戴伟,等.面向海量天文数据的分布式MySQL锥 形检索研究[J].天文研究与技术,2021.18(3):397-404.
关注SCI论文创作发表,寻求SCI论文修改润色、SCI论文代发表等服务支撑,请锁定SCI论文网!
文章出自SCI论文网转载请注明出处:https://www.lunwensci.com/jisuanjilunwen/57965.html