比对小工具开发之路...
博客专区 > Alfie 的博客 > 博客详情
比对小工具开发之路...
Alfie 发表于4年前
比对小工具开发之路...
  • 发表于 4年前
  • 阅读 4382
  • 收藏 84
  • 点赞 10
  • 评论 25

【腾讯云】买域名送云解析+SSL证书+建站!>>>   

摘要: 讲叙的是一个数据库比对小工具的成长优化之路,很详细哦!

接到任务,需要做一个数据比对的小工具,要求优先做好数据库表的数据比对,首先做了下分析,既然是小工具,我又是搞JAVA的,那只能选SWING了,脑子里当时稍微列了下实现步骤:

    第一步,实现单字段的比对 ;第二步,实现多字段的比对;第三步,实现表及比对字段的可配置划,第四部,能打包成EXE可执行文件;第五步,实现结果导出,第六步,优化比对核心模块;第七步,实现Excel与表比对;第八部,实现Excel间互相比对。

    ps: 考虑到最快的开发模式:举枪>射击>瞄准的开发模式,先将比对实现打通!也就是第一步到第四步,这里之所以把优化放在第五步,是因为上头要求先做好数据库比对,而Excel相关的就当然扔最后呐。

 首先比对肯定需要两个数据源:

            一个基准数据集(基准库)              一个比对数据集(比对库)

    其次分析数据结构:

          比对数据收集    |      字段                     行                 结果集                

        CompareView     |   FieldView     <     RowView   <   ResultView   

            (后来移掉ResultView,RowView包含两个FieldView的list,分别存放比对库和基准库差异的值)        

    再次分析比对准备流程:

        数据库配置 -> 获取表 -> 获取列 -> 设置比对基准 -> 设置比对列 ->设置完成

        基准库设置完成 -> 比对库设置完成 ->开始比对!  

    最后分析比对逻辑,分以下三种:

    1. 比对基准值,基准库有的比对库没有的,

    2. 比对基准值,比对库有的基准库没有的,

    3. 比对基准值,基准库有比对库也有,比队列的值不同的!

    接下来就开始了,SWING是完全不懂,不过也难不倒本人,首先准备环境,先去找了个JFrameDesigner插件

    第一步到第四步,做得何其顺利,(导出的先不管了)除了SWING因为实在接触得少,让我纠结了点,其它几乎都没碰到什么问题,接下来开始自测,修复一下七七八八的小问题,最后做个数据分页读取,终于跑起来了。

    ps:基准库是我们公司内网的数据库(51K多的数据量),比对库连的外省远程数据库(5K多的数据量),花费时间总共288秒!

    接下来就考虑优化的事了,继续分析下去,速度的优化大方向无非就是硬件,软件和环境,硬件和环境上没办法只能说我的东西有问题~  OK,不废话了,当时的想法就是从多线程和算法上下功夫!

    优化第一步,做线程,按分析逻辑的三种,每种分配一个线程,快了10几秒...

    优化第二步,做线程池,按分析逻辑的三种,每种分配一个10thread的线程池,又快了十几秒...(和内心想法差距过大,个人感觉此处应该要快更多,难道人品出了问题?)

        ps:这里啰嗦一句,玩线程的大家应该要知道,在excuse线程前,一定要构建好自己的tasklist

    优化第三步,线程方面的优化已经走到底了,接下来优化算法吧!

        ps:这一步下来真是累死累活,洗个澡,坐个公交车满脑子的都在想,这样如何?那样做又如何...拿着本子笔先后画了5,6页,OK说正题:

        草稿上最先出来的就是这个图了,(用QQ截图随手画的,撮了点)

       

    







    数据库数据抓取,之前已经加上的分页获取了,线程池的工作也完成了,优化的主要方向就是比对引擎和结果缓存和输出了!

    首先讲一下目前的比对模式,

        比对逻辑A , 获取所有的从标准库分页获取数据,通过key值,查询比对库,比对库没有的时候,返回 List<RowView>

        比对逻辑B , 获取所有的从比对库分页获取数据,通过key....................................................................................................................

        比对逻辑C,  获取所有的从标准库分页获取数据,通过key值,查询比对库,比对库有值,进一步进行比对,比对列的列值。

    ps:

            首先考虑减少连接关闭次数,将数据库的Connection,Statement 升级到compareView中!在程序关闭的时候,统一将CompareView中的Connection,Statement给关闭掉,OK,跑起来,发现有时候正常,有时候执行过程中会报resultset is closed. 还原statement在每次都开闭后,正常!(不明白,看来statement不能只create一次,优化力度不够

           其次考虑的是如何减少数据库的抓取次数,按目前的方式,ABC逻辑都是如下公式:

                抓取次数 = 分页查询A库的次数 * B库的所有行数

            很明显瓶颈在与B库,每次分页后,拿到的A库的每一个Key,都要去B库进行一次比对,这边我冲澡冲破了头,想到了一个数据库关键字  IN,

           我在做A库分页查询的时候,同步收集了所有的A库key列对应的值,然后查询B库的时候,我一次全部 where keycolumn in ('','',''...) ,

           想法很邪恶,效果很不错,比如A库分页每次1000条,如果按这种模式,我B库查询次数从1000次下降到了 1 次 

        再次对于算法的优化,目前的A,B,C三套分析逻辑是明显有重复的!

            ps:比如逻辑A,目前只分析出了标准库有,比对库没有的情况,实际上我们还可以通过这一次比对逻辑,同时分析出标准库有,比对库也有的情况!这样再执行逻辑B,执行出来的结果还是有三个LIST,而逻辑C这一步却在A就做完了!

      OK,到此为止,我的程序从288秒,优化到了65秒!很给力吧,先给图:

        最后,考虑的是如何输出的问题,比对的结果我也不可能全部放内存里面,大概算了一下

        java一个汉字字符占2字节,如果你一条记录有100个汉字,也就是一条记录占200字节,那么600万条数据就是12000000000字节。

        1G=1024M=1024X1024K=1024X1024X1024byte=1024x1024x1024x8字节=8589934592字节

        如果是600W条数据,那么所耗内存就是:12000000000/8589934592 = 1.4G

        一直放内存显然也是不行的。   

        这边目前我的思考模式是,增加一个ExportCache(单列模式), 这个cache里面有三个list,分别对应之前逻辑A,逻辑B,逻辑C对应的比对结果list,每次比对完毕的时候,往这个cache的对应list里add进去。

       我另外有一个执行导出动作--Export的Runable,在进入比对方法时,开启比对线程之前,开辟这个单独为执行导出的线程,让他一直在跑,判断如果cache里面的list有值了,那么我就做输出动作,输出完了从对应list里面给remove掉,当然每次也是1000条,哈哈!这个导出的线程就不在compare方法里面等待关闭了,开着就一直开着吧,后面关闭系统了再统一关闭就行了。

        


        说到这里,整个思路全部出来了,看在这么多字的份上,赞一个呗!  有什么优化的建议,欢迎大家留言回复!不慎感激!  

最后上张图,以正试听,界面大家就不要扔翔了!



  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 6
博文 8
码字总数 6237
评论 (25)
java9
看起来不错的呀。
Simon-Fish
太长了,友情支持一下。
Weathery
集合对比、中文检索、数据缓存三个方向都可以进一步提升你的程序执行效率。
xinall
能共享下吗?
Alfie

引用来自“Simon-Fish”的评论

太长了,友情支持一下。

鱼总点拨有功啊,还有大黄的支持!
Alfie

引用来自“Vivim”的评论

集合对比、中文检索、数据缓存三个方向都可以进一步提升你的程序执行效率。

非常感谢您的建议,
集合比对除了循环进行值比之外还有其它的方向吗?
中文检索没想到怎么用,
数据缓存考虑过,后来发现分析比读取慢,所以就没在DB Reader中做数据缓存了
Alfie

引用来自“xinall”的评论

能共享下吗?

整体完善了后可以有~
Glitter
为什么最近的截图都很模糊?14
vingzhang
很黄很暴力
whaon
点赞
胡东成
对数据库不熟悉。。。

我在做A库分页查询的时候,同步收集了所有的A库key列对应的值,然后查询B库的时候,我一次全部 where keycolumn in ('','',''...)

优雅先生
就这么点数据,65秒,感觉还是弱爆了啊
优雅先生
楼主别介意啊,只是随口说说。楼主考虑过如果每张表的数据量达到百万以上(这个很平常,反而是十万以下的数据很少见),那么这个运行时间是否会线性增长?那如果千万呢?不知道是否可以借鉴Hadoop的Map/Reduce?
我去年也写过一个数据比对脚本,源表数据大概100万,目标表数据大概10万,当然我比对的是关键的几个列,当时我估算后采取的是把所有数据导入到内存用Dictionay(.NET中的字典,类似Java中的Hashtable),然后外加.NET 4的并行处理,基本上是几秒出结果,当时脚本服务器的内存是16G,内存占用峰值大概为5G。
优雅先生
如果数据只是十万级别,完全可以考虑到全部加在到内存的哈希结构中处理。而如果楼主还想考虑数据增长情况下的运行效率问题,那么就有必要对比对算法重新设计,毕竟65秒-十万级数据,这个还是很慢的。
坏孩子
建个db link做对比,直接写sql,用完删了db link
Alfie

引用来自“美好的2014”的评论

如果数据只是十万级别,完全可以考虑到全部加在到内存的哈希结构中处理。而如果楼主还想考虑数据增长情况下的运行效率问题,那么就有必要对比对算法重新设计,毕竟65秒-十万级数据,这个还是很慢的。

您好,非常感谢您的批评和建议,谢谢!
首先文章中有提到,一个是局域网的数据库,一个是远程外省的一个数据库服务器,首先收到网络带宽的影响,而非都是本地库。
其次要考虑到硬件的因素,您是在脚本服务器上跑,而我是在自己的笔记本上跑,当年玩多线程的时候有发现CPU对线程的影响是非常大的,比如说I53代和core2在速度上天差地远,更何况你是在服务器上跑,你可以去玩一玩就知道了
再次你是一次读入在内存中比对,土豪啊!这对普通的用户怎么说都太奢侈了,如果人家是32位的XP呢?
不知道您有没有全部读完,文章后面有提到,600W条数据的换算,如果每条才占100个中文字符,内存就要消耗有1.4G(这还只是理论值!)
再一次感谢您的建议,谢谢!
Alfie

引用来自“坏孩子”的评论

建个db link做对比,直接写sql,用完删了db link

谢谢您的建议,这个完全可以有!
局限于数据库是人家的,需要考虑是否只有查询权限。
谢谢!
Alfie

引用来自“胡东成”的评论

对数据库不熟悉。。。

我在做A库分页查询的时候,同步收集了所有的A库key列对应的值,然后查询B库的时候,我一次全部 where keycolumn in ('','',''...)

是否考虑IN效率的问题?
in的是字段,而非子查询,不会出现笛卡尔积的情况,谢谢!
优雅先生

引用来自“Alfie”的评论

引用来自“美好的2014”的评论

如果数据只是十万级别,完全可以考虑到全部加在到内存的哈希结构中处理。而如果楼主还想考虑数据增长情况下的运行效率问题,那么就有必要对比对算法重新设计,毕竟65秒-十万级数据,这个还是很慢的。

您好,非常感谢您的批评和建议,谢谢!
首先文章中有提到,一个是局域网的数据库,一个是远程外省的一个数据库服务器,首先收到网络带宽的影响,而非都是本地库。
其次要考虑到硬件的因素,您是在脚本服务器上跑,而我是在自己的笔记本上跑,当年玩多线程的时候有发现CPU对线程的影响是非常大的,比如说I53代和core2在速度上天差地远,更何况你是在服务器上跑,你可以去玩一玩就知道了
再次你是一次读入在内存中比对,土豪啊!这对普通的用户怎么说都太奢侈了,如果人家是32位的XP呢?
不知道您有没有全部读完,文章后面有提到,600W条数据的换算,如果每条才占100个中文字符,内存就要消耗有1.4G(这还只是理论值!)
再一次感谢您的建议,谢谢!

现在4G内存的机器都很常见吧,而且你是为公司做的工具,不可能一直跑在你自己的32位XP上吧?
优雅先生

引用来自“Alfie”的评论

引用来自“胡东成”的评论

对数据库不熟悉。。。

我在做A库分页查询的时候,同步收集了所有的A库key列对应的值,然后查询B库的时候,我一次全部 where keycolumn in ('','',''...)

是否考虑IN效率的问题?
in的是字段,而非子查询,不会出现笛卡尔积的情况,谢谢!

不知道你的数据库是不是MySQL,对于MySQL的某些低版本col IN(val1, val2, val3,....valn)和col=val1 OR col=val2 OR col=val3...OR col=valn,尤其是n非常大的时候,性能差距还是非常大的。
×
Alfie
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: