Sybase 海量数据分页瞬间完成

来源:互联网 发布:百合小说 知乎 编辑:程序博客网 时间:2024/06/01 22:59

原理:类似游标+ top 函数分页

代码可读性比较差下面是分析:

分析1,假如有100W条的数据


分析2,假设10W条位置处的id是100001,假设20W条位置处的id是200001,假设50W条位置处的id是500001


分析3,缓存10W,20W...90W,把这些位置的id缓存起来,sql语句作为key把10w位置的id 100001,20w位置的id 200001,…50w位置的id 500001...这些位置的id位置数据缓存起来,使用sql作为key是因为不同的sql语句缓存的id位置也不同


总结,如果每页10条数据,那么就有10W页,如果翻到5.1W页,数据肯定就是在50W位置之后,sql查询的时候直接从50W条数据开始往后查找,时间复杂度100W/10个缓存点=10W的数据的复杂度,如果有100个缓存点那么就是1W条的时间复杂度,如果翻页刚好在缓存点之后的几页复杂度接近于0,如果在下一个缓存点之前时间复杂度相当于1W。平均算来相当于5k的时间复杂度。这样的效率可想而知


海量数据分页(100W条),首次分页大概为10秒左右。以后翻页基本上是瞬间完成。要求是无排序情况下。

目前sybase分页:

1,hibernate分页:hibernate分页前几页和后几页没问题,如果数据量大翻到30000页时就内存溢出了。而且效率慢。

2,存储过程分页:使用存储过程分页大数据量也不适合。效率低而且不支持并发。

jdbc分页好处:

1,效率高。

2,所有数据库通用。

3,支持大数据。

jdbc分页要解决2个问题。

1,取分页总数

    当没次翻页的时候都要这个数据,所以要把这个数据缓存起来(所以前面提到首次要10秒,这个要占用一部分时间,下次翻页就不用了)

2,取当前页数据

    如何取这个是重点,这个也要分2步骤

    1)找到当前页第一条数据的位置

           这一步也是关键。如果你每次从第一条找,那么找第50W条记录会浪费很长。解决这个问题也要使用缓存。假如50W条数据增加50个缓存点。那么翻到最后一页就从第50个缓存点开始查找,也就是说从第49W条开始查找。那么无论翻倒哪一页最差效率为1W条的效率。(这里有一个要求就是通过id排序,所以这个算法不支持其他字段排序)

    2)把这一页的数据取出来。

增加带排序功能请点击这里

源代码2.0下载,修改部分BUG

测试代码1.0下载,速度快不快试试就知道

点击打开链接源代码2.0下载,修改部分BUG

地方

 

分页代码

/** * jdbc分页add by wangmeng 2013-4-18 * 要求单表,无子查询,无关联查询  * @param sql 执行sql语句 * @param cls 封装数据表 * @param id  id列名 * @param startNum 从哪条开始。0...n * @param pageSize 每页条数 * @return */public Page findPageBySql( final String sql, Class cls,final String id, int startNum,final int pageSize) {final Page page = new Page();//分页信息记录总数和当前页数据try{String execsql = sql;String sql2 = sql.toLowerCase();long btime = System.currentTimeMillis();long etime ;            final Connection con = JDBCUtil.getConnection();            PreparedStatement stmt;            ResultSet rs ;String counthql=sql2; //计算count(*)的SQLint cacount = CacheUtil.getTotalSize(sql);//读取总数缓存            int total = 0;//返回count数if(cacount == -1){//没有缓存if(counthql.indexOf("order")>-1){counthql="select count(*) "+counthql.substring(counthql.indexOf("from"), counthql.lastIndexOf("order"));}else{counthql="select count(*) "+counthql.substring(counthql.indexOf("from"), counthql.length());}System.out.println(counthql);btime = System.currentTimeMillis();            stmt = con.prepareStatement(counthql);            rs = stmt.executeQuery();            rs.next();            page.setTotalCount(rs.getInt(1));            total = rs.getInt(1);            CacheUtil.setTotal(sql, total);}else{total = (Integer)cacount;            page.setTotalCount(total);}            if(total <=0){            return page;            }etime = System.currentTimeMillis();System.out.println("countsql处理时间:"+(etime - btime));btime = System.currentTimeMillis();            if(total < 1000){//小数据量处理System.out.println(execsql);            stmt = con.prepareStatement(execsql);            rs = stmt.executeQuery();            int var = 0;            while(var++<startNum && rs.next());List list = CloneUtil.cloneResultSet2List(rs,cls,null,pageSize);page.setData(list);            }else{//大数据量处理            String t = sql2.substring(sql2.indexOf("from")+5);//获取表名String idsql = "select "+id+" from "+t.trim().split(" ")[0]+" "; //先查询id位置的sqlif(sql2.contains("where")){//拼where子句if(sql2.contains("order by")){idsql += sql2.substring(sql2.indexOf("where"),sql.indexOf("order by"));}else{idsql += sql2.substring(sql2.indexOf("where"));}}int orderIndex = sql2.indexOf("order by");final String cachidsql = idsql; if(orderIndex == -1){//无排序可以增加缓存进行快速查找if(CacheUtil.isInitIndex(sql)){//有缓存使用缓存Entry<Integer, Object> entry = CacheUtil.getFloorEntry(sql, startNum);if(entry == null){}startNum -= entry.getKey();if(idsql.contains("where")){idsql +=" and "+id+" >= "+entry.getValue();}else{idsql +="where "+id+" >= "+entry.getValue();}idsql = "select top "+(startNum+pageSize)+idsql.substring(idsql.indexOf("select")+6);}else{//没缓存增加new Thread(){@Overridepublic void run() {try {Connection c = JDBCUtil.getConnection();ResultSet rs = c.prepareStatement(cachidsql+ " order by "+id).executeQuery();int i =0;int cap = CacheUtil.getIndexSize(sql);Map map = new HashMap();            while(rs.next() ){            if(i % cap ==0){            map.put(i, rs.getInt(1));            }            i++;}            CacheUtil.initPageIndex(sql, map);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}.start();}idsql += " order by "+id;}System.out.println(idsql);            stmt = con.prepareStatement(idsql);            rs = stmt.executeQuery();            int var = 0;            while(var++<startNum && rs.next());            int i = 0;            List ids = new ArrayList();            while(rs.next() && i++ < pageSize){//把缓存数据取出来            ids.add(rs.getObject(1));}etime = System.currentTimeMillis();System.out.println("idsql处理时间:"+(etime - btime));btime = System.currentTimeMillis();StringBuilder sbsql = new StringBuilder();if(orderIndex == -1){//无排序使用id>=?方式sbsql.append(id).append(">=").append(ids.get(0));execsql = "select top "+pageSize+execsql.substring(execsql.toLowerCase().indexOf("select")+6);}else{//有排序使用id=? or id=?sbsql.append(" (");for (int j = 0; j < ids.size(); j++) {if(sbsql.indexOf("("+id) != -1){sbsql.append(" or ");}sbsql.append(id +" = ").append(ids.get(j));}sbsql.append(")");}if(!execsql.toLowerCase().contains("where")){execsql += "where "+sbsql.toString();}else {execsql += " and "+sbsql.toString();}System.out.println(execsql);QueryBySqlResultSet qbc = new QueryBySqlResultSet(execsql,cls,pageSize);//使用hibernate取数据//            stmt = con.prepareStatement(execsql);//            rs = stmt.executeQuery();List list  = (List)getHibernateTemplate().execute(qbc);etime = System.currentTimeMillis();System.out.println("查询数据时间:"+(etime - btime));page.setData(list);            }btime = System.currentTimeMillis();new Thread(){public void run() {try {JDBCUtil.closeConnection(con);} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}};}.start();etime = System.currentTimeMillis();System.out.println("rs关闭时间:"+(etime - btime));}catch(Exception e){e.printStackTrace();}return page;}


 


CacheUtil缓存工具类

import java.util.LinkedHashMap;import java.util.Map;import java.util.Map.Entry;import com.metarnet.eoms.common.base.model.SQLCacheInfo;/** * 给数据库表记录数和Id增加缓存 * @author wangmeng  * */public class CacheUtil {private static LinkedHashMap<String,Object> lmap = new LinkedHashMap<String,Object>(){private static final long serialVersionUID = -3432076593791024110L;//创建一个LinkedHashMap匿名内部类最大size是30超过30自动删除第一个private final static int MAX_SIZE = 30;protected boolean removeEldestEntry(java.util.Map.Entry<String,Object> eldest) {return size()>MAX_SIZE;};};private CacheUtil(){};/** * 缓存总数 * @param key * @param value */public static void  setTotal(String key,int value){SQLCacheInfo info = (SQLCacheInfo)lmap.get(key);if(info == null){info = new SQLCacheInfo();}info.setTotalSize(value);lmap.put(key, info);}public static int getTotalSize(String key){SQLCacheInfo info = (SQLCacheInfo)lmap.get(key);if(info == null){return -1;}return info.getTotalSize();}/** * 缓存id位置 * @param key * @param map */public static void initPageIndex(String key, Map<Integer,Object> map){SQLCacheInfo info = (SQLCacheInfo)lmap.get(key);if(info == null){info = new SQLCacheInfo();}info.put(map);}/** * 返回id位置信息 *  * @param key  * @param index * @return */public static Entry<Integer, Object> getFloorEntry(String key,Integer index){SQLCacheInfo info = (SQLCacheInfo)lmap.get(key);if(info == null){return null;}return info.getEntry(index);}public static Entry<Integer, Object> getCeilEntry(String key,Integer index){SQLCacheInfo info = (SQLCacheInfo)lmap.get(key);if(info == null){return null;}return info.getCeilEntry(index);}/** * 返回缓存id位置的数量 * @param key * @return */public static int getIndexSize(String key){SQLCacheInfo info = (SQLCacheInfo)lmap.get(key);if(info == null){return -1;}return info.getIndexSize();}public static boolean isInitIndex(String key){SQLCacheInfo info = (SQLCacheInfo)lmap.get(key);if(info == null){throw new RuntimeException(key+"没有找到");}return info.isInitIndex();}}


缓存信息SQLCacheInfo

import java.util.HashMap;import java.util.Map;import java.util.TreeMap;import java.util.Map.Entry;public class SQLCacheInfo {/** * 第多少条,id值多少 */private  TreeMap<Integer,Object> IndexId = new TreeMap<Integer,Object>();public static final int MOD = 50;public static final int CAPTION = 10000;private int totalSize;public int getTotalSize() {return totalSize;}public void setTotalSize(int totalSize) {this.totalSize = totalSize;}/** * 根据条数返回id值 * @param index * @return */public Entry<Integer,Object> getEntry(int index){return IndexId.floorEntry(index);}public Entry<Integer,Object> getCeilEntry(int index){return IndexId.ceilingEntry(index);}public void put(Map<Integer,Object> map){IndexId.putAll(map);}public int getIndexSize(){if(totalSize < 10000)return -1;return Math.max(CAPTION,(totalSize / 50));}public static void main(String[] args) {SQLCacheInfo info = new SQLCacheInfo();HashMap map = new HashMap();map.put(10, 2);map.put(40, 2);map.put(60, 2);map.put(80, 2);info.put(map);System.out.println(info.getEntry(100).getKey());}public boolean isInitIndex(){return this.IndexId.size()>0;}}


 

原创粉丝点击