`
爱迪生的小屋
  • 浏览: 35641 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Infobright优化实践

阅读更多

Infobright优化实践

      统计系统后台用到了Infobright ICE社区版,记录10亿规模,出于灵活和省力的目的。日志入库过程并未作复杂处理,而是一条记录对应一条日志,所有的统计分析都是实时查询。最近日益感觉查询速度不足,于是做了一些研究和优化,成功将速度提升10倍以上,现将优化实践做个记录。

 

老少皆知的方法

    1. comment 'lookup':对于选择少于10000的字符串型字段,这是一个非常实用的优化

    2. 按特定顺序导入记录:日志最重要的属性是时间,我的日志也是按时间升序导入,因为时间本身没什么重复性,所以不用考虑第二,第三排序字段。

    3. 结果输入字段尽量精减:作为列存储数据库,查询过程用到的字段越少,读的数据就越少,最后select的结果就是where和group里用的条件。

 

我所尝试的方法

    1. 扩展comment 'lookup'的思路,将字符串字段先在mysql的库中建一个字典,入infobright库时转换为数字型主键。可以解决comment 'lookup'里10000个的限制;而且在数据导出时也是数据,减少导出文件的大小。

    2. 将字符型字段转换成数字:比如IP字段,完全可以转换成一个4byte的数字,不会丢失精度。再比如userToken字段,如果是比较短的字母和数字的组合,可以将里面的字母替换成0-9数字,虽然会丢失一点精度,但不同的token上仍然可以区分,可以在不是非常丢失精度的情况下获得近似正确的统计结果,对我而言是可以接受的。

    3. 日期的统计,往往有按年,月,日,小时,周期,季度都的需求,使用函数显然不合适。这里可以在表里为每一个需求多加一个字段,比如2001算起的第几年,第几月,第几日,第几个星期,占用空间不大,统计起来直接按照对应字段来group,速度提升显著。

    4. 更新Infobright版本,把我用的infobright版本从3.5.2提升到4.0.7,感觉上有20%的性能提升,免费的提升,不要白不要。

    5. 提高内存,服务器12G内存,Infobright推荐堆内存6G,我把它提高到了8G,减少了一些cache的使用。

    6. cache目录和data目录分两块硬盘,使用到cache的时候相当于硬盘的读写性能翻倍。

    7. 粗排序:我自己发明的名词,不知道有没有人提出过,基本原理是基于Infobright的数据集,为了能尽快发现一个数据集与查询条件是否相关,我们会使用到排序,而且是多字段的。问题出现在这里,当前面的排序字段重复性越低,后面的排序字段的作用就越小。比如我的日志表,第一排序字段是时间,单位是秒,第二排序字段是客户端类型,我发现由于同一秒内的请求量太少,客户端排序就显得没什么意义,根据客户端的搜索就得不到什么优化,如果时间单位是毫秒,那就更不会有同一时刻的请求出现,客户端排序就变得毫不意义。为了解决这个问题,我把第一排序字段换成了createhour,即前面第3条为了group by hour而添加的字段,第二排序字段还是client,这样一来,同一小时的记录数大大增加,查询条件里针对client的优化也出现了明显的速度提升,至于按照时间来排序,的确速度会略有下降,但是因为只是在一个小时的记录数内进行排序,速度还是非常之快。正所谓:天之道,损有余而补不足。这个优化非常成功,将综合性能提升了2-3倍。

 

特定条件下的关键优化

    如果一个查询是可以拆分的,则可以进一步优化。

    所谓查询可拆分,指的是查询可以通过where条件分成多个区间,每个区间的结果互不影响,将每个区间的结果组合就可以得到最终结果。

    比如:要查询日志表中每个月的请求数,我们会用这样的sql

            select createmonth, count(*) from access_log group by createmonth;

    这就是可以拆分,它可以按时间被拆分成一组sql

    select createmonth, count(*) from access_log where createtime between '2013-01-01' and '2013-02-28' group by createmonth;

      select createmonth, count(*) from access_log where createtime between '2013-03-01' and '2013-04-30' group by createmonth;

      select createmonth, count(*) from access_log where createtime between '2013-05-01' and '2013-06-30' group by createmonth; 

      select createmonth, count(*) from access_log where createtime between '2013-07-01' and '2013-08-31' group by createmonth;

     最后把每个查询的结果组合在一起就可以得到每个月的播放数。一般情况下,一个查询是否可以拆分凭经验就可以判断,基本上没有多表组合且没有distinct的查询都可以拆分。

     对于可拆分的查询,有两个强大的优化可以做,那就是:

     1. 多线程查询:要知道Infobright社区版是不支持一个查询语句多线程,这也是它被诟病最多的一点,但企业版又过于昂贵,不是一个普通的程序员可以决定买不买的。但是如果我们把一个查询拆分,就可以自己实现多线程查询,可以充份发挥服务器的性能,速度提高达8倍以上,这也是我这次所做的最成功的优化。

     2. 分批查询:如果一个查询的结果太大,Infobright会把它先保存到cache中,再一起返回,多了cache的读写,自然会比内存慢很多,如果把查询拆开,多次返回,可以保证所有的操作都在内存中,速度提升明显。

0
2
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics