zoukankan      html  css  js  c++  java
  • 在工作中遇到数据优化的一点感想

    一,前言

      先做一下场景描述:在mongodb中,我们维护了一个A表,保留近2日的点击信息。A表数据增长很快,每天300万左右。这样即使每日凌晨清理前天数据,到了晚上仍然会有近600万数据。

      有个业务需求:需要在不到1s的时间内根据uid查出A表对应的记录。

      问题:刚开始时每天也就几十万数据量,没什么问题。现在一到晚上数据量渐增到600万时,经常报查找超时。

    二,我能想到的优化

      很简单,1,针对uid建立索引。uid是一个36位长的字符串。2,mongo的有一种查找叫 find_one 。即查找到第一次出现的即可。

          3,分表。

    三,分表的思想

      分表是必须的,但如何分表呢。这就有技巧和经验了。

      经理和我关于怎么分表进行了一个小时的讨论(后来发觉他早想好怎么分了,就是想看看我的思路和他的能不能一致)。事后觉得他的分析思路很不错,特此记录下。说点题外话,我觉得学习这事吧。自己学明白不一定是真明白,能把别人讲明白才是真明白。所以在身边没有听众的情况下,写博客就是比较好的办法(哈哈,在自夸)。

      1.进入正题:我们的目标是调高查询速度。OK!造成查询慢的原因有什么呢:1,数据量大。2,文件体积大。

      所以600万条60G的数据查起来会比600万条60M的数据慢。有人会说,mongo存的是内存,mysql,oracle存的是文件。怎么会出现文件大小影响查询速度呢。事实上不然,个人见证了这个A表成长的历史,最早该表占用19G的大小。随着业务量的增长,A表越来越大。眼睁睁看着他2G,2G的吃硬盘,最后到接近80G。而服务器的可用空间从开始的73%降到40%。所以,mongo用的是虚拟内存,虚拟内存实际是物理内存的抽象,多数情况下,出于方便性的考虑,访问的都是虚拟内存地址,然后操作系统会把它翻译成物理内存地址。Swap也是虚拟内存引申出的一种。这样的话,你就涉及到地址偏移。文件巨大的情况下,查询效率会下降。(个人理解,欢迎指正)

      所以,我们可以试着给A表减肥。

      2.按逻辑分表

      事实上,处于数据完整性考虑。经理不希望缩减A表的字段。那么,另辟蹊跷。我们针对查询业务,专门拿出一个B表,专做查询用。按逻辑分,A是日志表,B是查询表。原先A表有10个字段,而且有的字段很大。现在B表仅需要4个字段。我估算过,相同数据量,A表是B表的三倍。这样我们可以认为查询效率提高3倍。该建索引照样建索引啊。

      3.按业务分表

      因为必须要保留2天的数据。所不能简单按日期,小时分表。但是,我们在B表有个字段C意义特殊,可以按照C字段分表。这样又把B查询表数据量减少一半。至此,我们相当于提高了3*2倍的查询效率。相当于我只需要从100万的数据中进行查找即可。

      4.总结1

      到此,经理的想法全部如上。先指出可取之处:1.再简单,明显的问题,也要先做分析。分析出文件大小会影响查询效率,其实分表也是。各位肯定比我聪明,我当时没想到。上来琢磨咋分表。没考虑减少表字段的可能。这就是土作坊和正规军的区别。(经理不混博客园,我拍马屁也没用)

      2.分表也要有章程。先按逻辑分,再按业务分。

      OK!想想,好像没啥了。就这样。

    四,继续深入研究

      以上是我在公司讨论研究出结果。优化也是按照上面的思路来的。优化完之后,果然系统运行正常,不再报错。事后我琢磨一下,现在的成果相当于,优化成从100万数据中查询。如果以后生意好了,数据量又翻了6倍呢?咋整。我们现在这个分表好像已经物尽其用了,数据必须保留2天的。唯一的C字段也被我用来分表了。

      下班我和室友讨论了一下这个问题。其实还有办法优化。感谢@fengbohello的技术支持。

      前文描述到我们从B表查询时是按照uid一个36位长的字符串进行查找的。嘿嘿,我们可以在uid身上做文章。uid大概这样:"AB4A821C5DB3930C32A34000799F2D710E36"。

    你在插入B表前,先做一步操作:table等于uid的每一位相加。uid每一位都是一个char,这样你最后得到的肯定也是一个char。一个char有8bit。所以table就有2的8次方的可能。比如table='10011011'。这里要用加运算,别用与运算和或运算。因为这两个运算得出0,1分布都是1:3或3:1。这样得出的散列结果不会均匀分布。

      我们的uid是随机的,所以你最后将uid插入表时会随机插入到table1='10011011'的表中。同样,当你拿到uid做查询时,做相同处理后,你就立即知道你要去table1中查询对应的记录。综上所述,我们相当于根据uid进行散列,对B表又一次分成了256个分表。不但表变小了。而且400万进行2分的话,相当于2的22次方。散列后,我减少了8次2分查询。

      嗯,先这样。欢迎大家指正或提出好的思路。 

  • 相关阅读:
    解决GitHub下载速度缓慢的问题
    什么是“个人商业模式”?就是一个人出售自己时间的方式
    phpstudy如何安装ssl证书
    心不动——王阳明最可怕之处
    人间立命王阳明
    计算机视觉数据集
    ECG心电图数据2
    ECG心电图数据1
    梯度下降VS随机梯度下降
    SGD
  • 原文地址:https://www.cnblogs.com/zhangyabin---acm/p/5955001.html
Copyright © 2011-2022 走看看