近期,数据中心系统负荷大,mysql服务器的CPU动辄高达90%以上。代码和数据表存在很大优化空间。
这里分享一个定时任务批量处理数据的优化过程。

先介绍下面2张数据表
| 字段 | 数据量 | |
|
platform_order 平台交易订单表 |
包括 主键自增id、客户id、客户名称(冗余字段)、服务商id(levy_id)、服务商名称(levy_name,冗余字段)、 付款方式、付款状态、收款人、收款人收款账号(卡号/支付宝/微信)、项目id、付款金额、渠道商、销售代表、 创建时间、最近更新时间、付款完成时间,等等。 |
550w,每天增量3w 宽表,有多达54个字段。 |
|
levy_info 服务商信息表 |
字段包括 服务商id(levy_id)、服务商名称(levy_name),等若干字段 | 50条,基础信息表,很少新增 |
项目程序里有一个定时任务,每间隔5分钟,定期为platform_order的冗余字段levy_name赋值。也就是,根据levy表里的信息来更新platform_order表。
我相信这是绝大多数程序员的实现方式。
【第一步】求count: select count(1) from platform_order where levy_name is null
【第二步】分页从数据表获取 levy_name is null 的记录,例如每页1000条,放到List集合里。
【第三步】遍历List集合里的元素,根据记录的levy_id去查levy_info表,得到levy_name,执行SQL: update platform_order set levy_name=#{levy_name} where id=#{id}
这个定时任务启动后,不停刷日志,耗时≈3min
【第一步】求count:SQL同上
【第二步】如果count>0,则执行一条update语句: update platform_order a join levy_info b on a.levy_id=b.levy_id set a.levy_name=b.levy_name where a.levy_name is null
这个实现方式,java着实少了许多行代码,不过,数据库倒是出现慢sql了。 count耗时≈2s + update语句耗时10~12s = 整个job耗时≈15s 。
【第一步】
不再是傻瓜式地一个 levy_name is null 条件了。而是再加一个 id>#{maxId} 条件。 maxId 值从哪里来?每次定时任务执行完后将最大记录id缓存起来。当然,服务启动后第一次是没有缓存的,就让maxId=0。
再者,执行的sql不是简单的count,而是 select levy_id, min(id) as minId,max(id) as maxId from platform_order where id>#{maxId} and levy_name is null group by levy_id
【第二步】
上面的分组查询得到一个List集合,遍历集合元素,同样根据levy_id查levy_info表得到levy_info记录。
然后,如果你跟得上我的节奏,你应该能猜到,执行这样一个SQL:
update platform_order set levy_name=#{levy_name} where levy_id=#{levy_id} and id between #{minId} and #{maxId} and levy_name is null
View Code
顺便说一嘴,根据levy_id获取levy_info记录,我使用了缓存,缓存24h,豪横吧~
【第三步】
缓存最大id ---> maxId
经过这个性能优化之后,job的耗时在100ms~200ms之间,这个耗时足可以令伙伴们尖叫!

11)单表字段数不要太多,建议最多不要大于50个。过度的宽表对性能也是很大的影响。
12)MySQL在处理大表时,性能就开始明显降低,所以建议单表物理大小限制在16GB,表中数据行数控制在2000W内。
业内的规则是超过2000W性能开始明显降低。但是这个值是灵活的,你可以根据实际情况进行测试来判断,比如阿里的标准就是500W,百度的确是2000W。实际上是否宽表,单行数据所占用的空间都有起到作用的。
13)如果数据量或数据增长在前期规划时就较大,那么在设计评审时就应加入分表策略,后续会有专门的文章来分析数据拆分的做法:垂直拆分(垂直分库和垂直分表)、水平拆分(分库分表和库内分表)。
我今天看到了一个ruby代码片段。[1,2,3,4,5,6,7].inject(:+)=>28[1,2,3,4,5,6,7].inject(:*)=>5040这里的注入(inject)和之前看到的完全不一样,比如[1,2,3,4,5,6,7].inject{|sum,x|sum+x}请解释一下它是如何工作的? 最佳答案 没有魔法,符号(方法)只是可能的参数之一。这是来自文档:#enum.inject(initial,sym)=>obj#enum.inject(sym)=>obj#enum.inject(initial){|mem
我真的只是不确定这意味着什么或我应该做什么才能让网页在我的本地主机上运行。现在它只是显示一个错误,上面写着“我们很抱歉,但出了点问题。”当我运行railsserver并在chrome中打开localhost:3000时。这是控制台输出:StartedGET"/users/sign_in"for127.0.0.1at2013-07-0512:07:07-0400ProcessingbyDevise::SessionsController#newasHTMLCompleted500InternalServerErrorin55msNoMethodError(undefinedmethod`
好的,所以我有了我正在使用的应用程序的这种方法,它可以在生产中使用。我的问题为什么这行得通?这是新的Ruby语法吗?defeditload_elements(current_user)unlesscurrent_user.role?(:admin)respond_todo|format|format.json{render:json=>@user}format.xml{render:xml=>@user}format.htmlendrescueActiveRecord::RecordNotFoundrespond_to_not_found(:json,:xml,:html)end
你能解释一下吗?我想评估来自两个不同来源的值和计算。一个消息来源为我提供了以下信息(以编程方式):'a=2'第二个来源给了我这个表达式来评估:'a+3'这个有效:a=2eval'a+3'这也有效:eval'a=2;a+3'但我真正需要的是这个,但它不起作用:eval'a=2'eval'a+3'我想了解其中的区别,以及如何使最后一个选项起作用。感谢您的帮助。 最佳答案 您可以创建一个Binding,并将相同的绑定(bind)与每个eval相关联调用:1.9.3p194:008>b=binding=>#1.9.3p194:009>eva
(跟进我之前的问题,Ruby:howcanIcopyavariablewithoutpointingtothesameobject?)我正在编写一个简单的Ruby程序来在.svg文件中进行一些替换。第一步是从文件中提取信息并将其放入数组中。为了避免每次调用此函数时都从磁盘读取文件,我尝试使用memoize设计模式-在第一次调用后的每次调用中都使用缓存结果。为此,我使用了一个在函数之前定义的全局变量。但是,即使我在返回局部变量之前将该变量.dup为局部变量,调用该变量的函数仍在修改全局变量。这是我的实际代码:#memoizetokeepfromhavingtoreadoriginalfi
当我刚刚运行middleman时服务,all.css编译得很好,只包含对+box-shadow(none)的调用:/*line1,/home/yang/asdf/source/stylesheets/content.css.sass*/div{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}但是当我构建网站时,我得到了这个Sass/Compass错误:$middlemanbuildSlim::EmbeddedEngineisdeprecated,itiscalledSlim::EmbeddedinSlim2.0
所有题目均有五种语言实现。C实现目录、C++实现目录、Python实现目录、Java实现目录、JavaScript实现目录题目n行m列的矩阵,每个位置上有一个元素你可以上下左右行走,代价是前后两个位置元素值差的绝对值.另外,你最多可以使用一次传送阵(只能从一个数跳到另外一个相同的数)求从走上角走到右下角最少需要多少时间。输入描述:第一行两个整数n,m,分别代表矩阵的行和列。后面n行,每行m个整数,分别代表矩阵中的元素。输出描述:一个整数,表示最少需要多少时间。
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它
我刚刚更新了我的gem,当我尝试运行Guard时,出现以下错误:Guard::RSpecDEPRECATIONWARNING:The:clioptionisdeprecated.Pleasecustomizethenew:cmdoptiontofityourneed.这是我的Guard文件:guard'rspec',cli:'--drb'dowatch(%r{^spec/.+_spec\.rb$})watch(%r{^lib/(.+)\.rb$}){|m|"spec/lib/#{m[1]}_spec.rb"}watch('spec/spec_helper.rb'){"spec"}#Ra
这是字符串:04046955104021109我需要这样格式化:040469551-0402-1109用ruby做到这一点的最短/最有效的方法是什么? 最佳答案 两个简单的插入就可以了:example_string.insert(-9,'-').insert(-5,'-')负数表示您从字符串末尾开始计数。如果您愿意,也可以从头数起:example_string.insert(9,'-').insert(14,'-') 关于ruby-用ruby将2个破折号插入这个字符串的最短方法是