日期:2014-05-18  浏览次数:20737 次

数据库查询——性能调优~
本帖最后由 niushuai666 于 2013-12-06 16:26:19 编辑
现在项目出现了一个性能瓶颈:

我有A/B/C,3个表

现在通过B查询状态为1的记录,大概4000条。然后遍历这4000条:
    在C表(50万记录)查找id和B表id相同的记录

所以,性能瓶颈就是C表根据id查询。所以需要执行4000次查询。再包括建立连接、断开连接之类的开销。现在完成这个模块大概需要4分钟左右。

我现在想优化的思路是这样:

通过1次查询把C表的信息全部读进内存。但是问题是,如果我没有任何处理就读取,那么返回的是List<Object>对象,我需要完成4000 * 50万遍历才能完成这个任务。这样就更悲剧了。 所以,我想
select * from C where id in (1,2,3,4,5,...4000); 然后把这些结果装到一个
HashMap<B表id, List<Object>>。这样我用到的时候根据id就可以拿。

不知道SimpleJdbcTemplate有这样的函数吗????在线急等~~~

------解决方案--------------------
如果C表数据不怎么变化的话,可以考虑服务启动时,做个将C表加载到内存的任务,数据结构使用HashMap<B表id, List<Object>>,用的时候直接map.get(B表id)。
C表数据发生变化时,内存里的map对应的id对应的list也相应进行更新。

这要考虑内存,如果C表字段比较多,可能会占用很大内存。如果有条件,可以搞个缓存服务器。
------解决方案--------------------
SimpleJdbcTemplate不是有queryForObject(String sql,RowMapper rowMapper,Ojbect... args)方法吗这个方法就是返回你rowMapper的mapRow方法所返回的对象所以楼主只要利用BeanPropertyRowMapper进行属性和数据库字段的自动映射

Map<Integer,List<C>> map=new HashMap<Integer,List<C>>();
(Map<Integer,List<C>>)simpleJdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper(C.class){
   //这里重写下rowMapper方法把获得的C对象放到map中就是了
   public Object mapRow(ResultSet rs,int rowNum){
     //原来的方法就是会返回c对象了
     C c=(C)super.mapRow(rs,rowNum);
     //接下来只需要把这个c对象放到map中返回map即可
     Integer id=c.getId();
     List<C> list=map.get(id);
     if(list==null){
       list=new ArrayList<C>();
       map.put(list);
     }
     list.add(c);
     return map;
   }
   
},args)

------解决方案--------------------
楼主用过4楼和5楼说的多表连接么?如果有建立索引,性能应该不差才对。

Select * 
From c Join b On c.id = b.id 
Where b.state=1

其中,b表的state上要建立索引,c表的id上也要建立索引(不过估计这个字段是主键可以不用索引)。

如果还觉得连接性能不足,Oracle环境下,可以把C表建立为“哈希聚簇表”。
------解决方案--------------------
完整的看了一下上面的帖子.
select * from C where id in (1,2,3,...4000);
以及
select C.* from C where exists (select 1 from B where B.status = 1 and C.id=B.id) 

这里边,查询本身,可能费不了太长