数据库作为存储数据的介质,其包含数量庞大的数据表和复杂的数据关联。为确保数据库中数据的一致性,需要在数据表间定义一些约束关系,并引入外键(foreignkey)概念,用于建立和加强两个表数据之间的链接关系,即通过将表中某一字段或多个字段映射到另一个表中,创建两个表之间的约束关联。目前,采用外键设计的数据库已在传统行业中广泛使用,其优点主要是从数据库底层实现了数据的完整性和一致性,软件底层数据库开发与软件应用层开发相对透明,上层应用开发人员无需完全了解数据库设计规约。随着大数据时代的到来,互联网的数据容量呈现指数级增长,传统行业的应用软件逐渐转向互联网应用模式。由于外键字段执行写入操作时,需实现外键约束逻辑,对涉及外键校验的数据表加同步锁。如果写入操作不按照某种顺序执行,则造成外键校验不通过。因此,互联网行业应用不推荐使用外键。例如,数据表A关联数据表B,在用户执行写入操作时,新增表A数据的操作应在新增表B数据的操作之后,删除表A数据的操作应在删除表B的操作之前。
为满足大数据时代用户新需求,需要将通过客户端访问的模式转向通过浏览器访问的模式。数据表的数据量逐渐扩增且存在极为复杂的多表多字段外键依赖关系。在搭建数据库集群实现数据同步过程中,极易出现因外键冲突导致同步业务困难问题。如果重新设计底层数据库结构,消除已有外键依赖的数据表必然大幅增加开发成本。传统的解决方法是通过递归暴力查找外键冲突,此方法需反复访问数据库来查找外键依赖,造成IO操作频繁,影响了整体业务的性能。
本文提出一种外键关联有向图模型算法,将数据表之间的外键关系以有向图的形式展现,方便分析造成外键冲突的原因。根据数据库提供的SQL语句实现有向图生成算法,并将有向图转化为邻接矩阵,为解决外键冲突提供元数据。在此基础上,提出以邻接矩阵作为输入数据、以拓扑排序算法作为数据处理方法的原子性序列生成算法,解决外键冲突问题。
数据表外键依赖关系转化为有向无环图方法的步骤如下:
步骤1获取数据库的数据表集合T={ta,tb,tc,td,te},令T=V。
步骤2获取ti.fk与tj.rfk,得到Reference(ti.fk,tj.rfk)。
步骤3令ei=Reference(ti.fk,tj.rfk),即一条从ti指向tj的有向边,构建G(V,E)。
步骤4由数据库的外键约定可知,外键不存在循环依赖,即不存在环,G=DAG。
根据1.1节给出的将数据表之间的外键关联转换为有向图模型方法,DAG可以直观地展现外键依赖关系,但是DAG不能直接作为应用程序的输入数据交给计算机处理。因此,通常会将DAG转化为邻接矩阵,以方便数据存储和外键冲突解决处理。本节的主要研究工作集中在如何通过程序执行SQL语句获取T和Reference数据,以及设计并实现将外键依赖关系转化为邻接矩阵的方法。以oracle数据库为例,将DAG转化为邻接矩阵的SQL代码如下:
输入待执行写入操作的数据表ta
输出邻接矩阵表
1.begin
2.selectdistinctparent,child
3.fromuser_constraints//step1
4.innerjoinuser_constraints//step2
5.onr_constraint_name=constraint_name
6.where(constraint_type='fk'
7.orconstraint_type='rfk')//step3
8.connectbyparent=priorchild//step4
9.startwithparent='ta'//step5
10.end
本文的研究重点在于如何通过SQL语句生成邻接矩阵,该SQL语句的详细功能如下:
4)确定存在外键依赖的表,将无向图转为有向图。其中,connectby表示将每一行的数据按链式的层次关系检索,prior关键字表示指针的指向,放置在连接关系两列中的某一列,prior所在的一侧表示入度,另一侧表示出度。
5)用startwith关键字来标识查找图型结构的起始节点,需要执行写入操作的起始节点,即程序的输入。
根据外键有向图模型,分析写入操作的执行顺序可得出以下结论:执行插入操作需满足插入节点的出度为0;执行删除操作需满足删除节点的入度为0;更新操作可视为插入新数据,且删除旧数据。更新前的数据为删除的旧数据,更新后的数据为插入新数据。
步骤1指定用户需要执行写入操作数据表为起始节点。
步骤2从当前节点开始,访问该节点,并标记该节点为已访问过的节点,防止递归回溯出现重复访问。
步骤3判断该节点是否存在未被访问的子节点,若无,则执行步骤4,若有,则判断未被访问的节点入度是否为0。若入度为0,则访问该子节点,跳转到步骤2,否则执行步骤5。
步骤4如果该节点为根节点,则访问完毕,否则执行步骤3。
步骤5标记该节点的入度为1,跳转到步骤3。
实验硬件环境采用IntelCoreTMi5-9400CPU@2.9GHz、16GBDDR5内存和2TB机械硬盘;软件环境采用MicrosoftWindows10操作系统oracle数据库、JavaDevelopmentkit8开发工具包、NaviCat数据库可视化工具、jprofiler性能测试工具和IntelliJIDEA开发工具等。
实验将CPU利用率和内存消耗作为性能评估依据。CPU利用率是反映系统忙闲程度的指标。CPU利用率稳步上升,且数值不会过高,表明程序运行状态良好。当CPU利用率在某一时刻开始下降时,表明IO线程开始执行访问数据库,占用了CPU线程的工作;内存消耗是反映系统资源占用情况的指标。内存占用越高,表明程序运行过程中资源占用越多。当内存在某一时刻开始减少,表明jvm的垃圾回收线程开始工作,清理程序运行中不需要使用的资源。垃圾回收线程工作需要暂停CPU线程的正常运行。若CPU利用率和内存消耗出现频繁的抖动现象,则表明CPU线程处于阻塞状态,应用程序会出现明显的卡顿,影响用户体验。
为验证算法的准确性与泛化性,本文实验在不同的数据库应用场景下,对本文算法和传统算法进行性能比较。实验1为某学校的OA系统,实验采集了该管理系统的20张表,表中的数据主要为文本格式,有5张存在外键冲突的数据集;实验2为某公司的业务数据管理系统集群,实验采集了该数据库的20张表,表中的数据主要为文本和图片格式,有100张存在外键冲突的数据集;实验3为某公司的分布式多媒体文件存储系统,实验采集了该数据库的500张表,表中的数据主要为音频和视频格式,有200张存在外键冲突的数据集。