项目的开发终于只剩了我一个,自己瞎搞终于抠完了,发现将近100万的数据量根本跑不动,页面就剩一个圈圈在转,于是只能改代码优化.
逻辑中有先把符合规则的数据select 出来,然后处理一下再一条条update和insert.
首先把update 写成batch update
// for(Match match:updateMatchList){
// executor.update("MATCH.updateMatch", match);
// batch++;
// if(batch==500){
// LOG.info(""+i);
// executor.executeBatch();
// batch=0;
// i++;
// }
// }
把insert into 写成insert into ()values(...),(...),(...)的形式, 改善很小没啥用
2.然后想到改sql, 希望把n个sql并成一条
于是把select的记录把id取出拼成数组,写成update ... where id in(...)的形式,但这样由于id太多,sql太长,结果超出了mysql的允许大小.并且一次取出超过100000条数据在内存会out of menory,后来又把这些每50000条记录拆分操作,没报错但还是很慢.
<insert id="saveMatchClassfication" parameterClass="java.util.List">
insert into matchClassfication (
match_id,
class_id,
priority,
created_at
)values
<iterate conjunction =",">
<![CDATA[
(#matches[].id#, #matches[].classId#, #matches[].priority#, now())
]]>
</iterate>
</insert>
<update id="updateMatchClassIdBatch" parameterClass="java.util.HashMap">
update matchedVideo
set class_id=#classId#
where id in
<iterate close=")" open="(" conjunction="," property="idList">
<![CDATA[
#idList[]#
]]>
</iterate>
</update>
3.后来受同事启发一开始就不应该把记录先取出再处理,而应该直接用sql处理, 这样既不需要update上万次也没有out of menory的风险.于是稍微调增额业务处理的顺序,然后用两句sql搞定.然后发现数据量大sql的效率极低,甚至低于修改前.后来检查了一下sql,发现在where 中用了 is null,这样不会走索引,百万级数据会直接卡死.于是又修改了业务处理的顺序,避免这种问题.
4. 总结 :
a.能优化逻辑先优化逻辑,避免把表中大量数据一次取出的情况
b.避免一大批数据要一条一条update/insert的情况
c.写sql时避免关联很大的表,最好能用表中的一部分数据取出成一个新表再做关联
d.对于索引失效的情况得注意
e.适时用存储过程等做优化
f.对于读操作数据量大时要用缓存,避免每次都和数据库打交道
g.若还是很慢无法忍受,只能改成异步操作,每次用户点完直接返回并加上恰当的提示不至于让用户一直等在那无法操作.