20
2018
01

库存系统性能优化感想-灵感很重要

    最近两周做了一个库存系统的优化,其实工作量并不是很大,大概就用了几天的时间,但是对系统的影响是特别大的。

    写这篇文章,主要是为了说明灵感的重要性,对于做性能优化这件事,就是一件再普通不过的事,并没有什么可说的。

    故事还得从一年半以前说起(2016年5月库存系统正式上线运行),库存更新功能最初就是使用Entity Framework框架做的,功能有点复杂,那么开发人员就循规蹈矩用一惯的方式去开发,保存数据就是一条数据一条SQL这种方式,比如说,一次性保存或更新一年(算365天)的数据,那么,保存的数据最多是 365*3 (库存表、日志表、房态自动清零表),一条一条提交到数据库,那得提交1095次,这个时候虽然速度慢点,倒还不算太慢,也是因为数据库总数据量还没多大,后面又加了业务,保存时数据最多是 365*5 (库存表、日志表、房态自动清零表、数据防重表、囤单表),这个时候光执行SQL就得是1825次,还包括一些数据查询操作,逻辑判断操作,还有Mysql数据库表数据量非常大的情况下,这种速度真的慢到事务100%超时,数据保存不成功,现在只能把每次操作时间设置短点,一般是一个月到三个月(30天~90天)这个数据才能勉强保存成功,但等待时间也挺长的。查了下现在(归档移走了部分数据之后),库存表数据近3千万(select count(*)  需要47s),日志表查不出来,查了几分钟还在loading,我怕内存爆掉就停掉了,反正是库存表的N倍,之前有统计是大于1亿的数量。

    最近优化这个问题时经过测试,相比之前的保存超时,现在整个查询、计算、保存过程,更新一年的数据只需要2s~3s的时间,这个跟之前真的是天与地的差别了。所以,我为什么说灵感非常重要,之前一年多的时间都没有想到这种解决方法,为什么现在几天时间就解决了,说到底还是灵感的问题,但灵感应该不是那么容易出现的(如果天天有灵感出现,那可以当科学家了)。这件事的原因就是最近在考虑过年放假的事,要保证这个年过得顺利,每个系统或模块的直接负责人都要尽量想办法让自己负责的那块功能在过年期间不出问题,否则“后患无穷”。这个性能问题,我那几天几乎是走路吃饭睡觉都在想解决办法,突然有一天一道灵光闪过就想到了方案,有了方案之后,通过几天的时间努力去实现,终于是达到了想要的效果。


技术实现

示例,比如更新一年的数据(365天)

原来EF方式,新增数据类似:

insert into itemcontractstock……………………

insert into itemcontractstock……………………

insert into RecoverRoomCount…………………

insert into RecoverRoomCount…………………

…………………此处有5个表新增的insert语句,共365*5条……………………………

这种一条一条执行,最少几分钟,或者直接数据库事务超时保存不了。


新的SQL语句批量处理:

.Net代码拼接语句:

        public static string GetItemStockDateUnionSQL(List<DateTime> dateList, string tempTableName = "tbDate")
        {
            if (dateList == null || dateList.Count == 0) return string.Empty;
            StringBuilder sb = new StringBuilder();
            sb.Append("(").AppendLine();
            for (int i = 0; i < dateList.Count; i++)
            {
                if (i == 0) sb.AppendFormat("select '{0}' d", dateList[i].ToString("yyyy-MM-dd")).AppendLine();
                else sb.AppendFormat("union all select '{0}' d", dateList[i].ToString("yyyy-MM-dd")).AppendLine();
            }
            sb.Append(")").Append(tempTableName).Append(" ").AppendLine();
            return sb.ToString();
        }

拼接好的sql类似于这样:

(
select '2018-01-16' d
union all select '2018-01-17' d
union all select '2018-01-18' d
union all select '2018-01-19' d
union all select '2018-01-20' d
-- 更多日期
)tb1


那么一张表插入语句就一条,类似这样:

INSERT into RecoverRoomCount(StockId,Date,TaskStatus)
select s.StockId,DATE_ADD(DATE_ADD(tb1.d,INTERVAL 3 DAY),INTERVAL 5 HOUR),0
FROM
(select * from itemcontractstock where ShareGroupId=117484 and ProviderId=6604) s
join 
(
select '2018-01-16' d
union all select '2018-01-17' d
union all select '2018-01-18' d
union all select '2018-01-19' d
union all select '2018-01-20' d
-- 更多日期
)tb1
on s.Date =tb1.d


更新一张表也是一条语句,类似:

update itemcontractstock set ModifiedByName='test' -- 更多列更新
where ShareGroupId=1 and ProviderId=1 and `date` in
(
select tb1.d from 
(
select '2018-01-16' d
union all select '2018-01-17' d
union all select '2018-01-18' d
union all select '2018-01-19' d
union all select '2018-01-20' d
-- 更多日期
)tb1
)

这样一来,5个表,也就5条语句,那么每一条语句花个几百毫秒,整个执行完也不过几秒钟。


    分析了一下,我这边把一次业务操作和程序内部逻辑操作对比了一下,原来本质上有区别,才会导致原来的逻辑不合理。我来作个比喻,界面上点击一个按钮一次更新一批(365天)数据,而之前的程序逻辑是分成365个小任务,一个一个更新。相当于把一件大事分成365件小事,而且关键问题是给同一人做(如果是分给多人做那也可能会成为合理的逻辑),这就造成了问题,次数多了忙不过来就慢了,反正是同一人做,还不如整件事一次做。


小结:

1、灵感是可遇不可求的东西,很珍贵

2、要多思考才会有更多的灵感,灵感大多数据时候不会凭空降落

3、开发是一门艺术,引用别人说的一名话:计算机编程是一门艺术,因为它将积累的知识运用于世界,因为它需要技巧和灵性,更是因为它能制造美好的东西。一个潜意识里把自己视为艺术家的程序员,会更喜爱他的所做,也必将做的更好。



版权声明:
作者:真爱无限 出处:http://www.pukuimin.top 本文为博主原创文章版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接.
« 上一篇下一篇 »

相关文章:

评论列表:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。