现在的位置: 首页 > 综合 > 正文

数据库性能优化

2017年08月04日 ⁄ 综合 ⁄ 共 1332字 ⁄ 字号 评论关闭

    最近项目曝出了性能问题,这两天一直忙于此。先是大量测试找出具体现象的出现规律,然后据此分析问题大概出在哪里,最后寻求解决办法。

    背景简介:

    1、产品是DVB相关的,问题是出在android平台(基本是在android2.3、硬件配置相对来说比较低的一些手机上)的DVB player上;

    2、空中DVB的EPG数据会定时(间隔时间很短,10s以内)发送一次,而且当前频点(一个频点会有多个节目,每个节目有七天的数据)的EPG数据会很集中地发送过来。

    3、切换频道后(可能还在上一次播放频点上,也可能不在同一频点上),第一批过来的EPG数据,底层库会如实丢给player(后续再收到相同的EPG数据会被底层直接丢弃);

    4、player收到数据后会判断相关数据库表中是否存在该数据,如果不存在则插入,否则丢弃;

    5、视频render用的是opengl。

    一开始怀疑是render消耗了太多资源(测试结果显示,在有些android2.3设备上,opengl的性能还是比较低的)。后来测试中发现每换一次频道,大概过7、8s就会看到信号弱的提示,非常有规律。这个信号弱是player超过2s没有收到视频数据而发出的。通过log来看,每次出现信号弱的时候都有大量的EPG数据发送过来。把处理EPG存储的相关代码注释掉发现就没有这个现象了;把EPG存储打开,关闭render,在配置低的手机上有时候也能看到,但不是很明显。到这里基本就能知道是数据库操作影响了整体性能。同时在同一频点换频道时,虽然EPG数据本地都有了,但是还是会出现信号弱,这说明写数据库之前的操作是问题所在。


    优化前EPG存储的做法:

    1、每次insert都是单独的一次提交;

    2、每次insert之前先select(用四个字段判断数据是否重复)一下,看看表中是否已存在此条数据(测试结果也证实这样做的效率是极低的)。

    优化后EPG存储的做法:

    1、将判断重复用的四个字段做unique约束(数据库内部会根据这四个unique建立一个索引,然后根据索引来判断数据是否重复),然后用INSERT OR IGNORE替换之前的INSERT(去掉select动作);

    2、INSERT语句只编译一次,后续插入操作只需修改绑定参数即可(调用SQLiteDatabase对象的compileStatement方法编译sql语句);

    3、引用事务操作(多条INSERT做一次提交);

    4、延迟处理。建立一个epg缓存队列,收到数据解析后存放到队列里,然后另外开一个Timer每隔5s从队列中最多取100条数据写入数据库,timer每次执行的所有INSERT都作为一个事务处理。由于换频道后收到重复数据的概率比较大,所以换频道之前先停掉Timer,然后清空epg缓存队列,换频道结束后再开启Timer。

    在做完前三件事情之后,测试发现情况大有改变,但在某些码率比较大的节目里还是能看到信号弱的提示,所以就有了第四条优化策略。这里也说明了,频繁地往存储设备(android数据库最终还是在SD卡上)上读写大量数据是很低效的。做了第四项改进后,bug彻底解决了。

【上篇】
【下篇】

抱歉!评论已关闭.