数据库查询——性能调优~
现在项目出现了一个性能瓶颈:
我有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)
这里边,查询本身,可能费不了太长的时间,
问题的关键是可能有不少于4000条记录,如果是一个id对多条C的记录的话,
如果这个表的字段个数比较多,势必读取数据时,要费不少时间.
既然C表的数据可以缓存(没什么写操作? 对否?),对吧,同时id是整型的话,不妨用TreeSet<int, List<Object>>缓存起来,
这是一颗排好序的树,取某个id对应的value也非常快.
------解决方案--------------------共同学习啦~
嗯,有索引、主键的时候,会影响插入的操作效率,有些项目因为增删操作非常频繁,就弃用索引了的。
不过不用主键、索引,错失浪费数据库的一大特性啊。