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

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

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

sybase怎么分页 sybase 分页查询_Sybase

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

sybase怎么分页 sybase 分页查询_大数据_02

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

sybase怎么分页 sybase 分页查询_大数据_03

总结,如果每页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(*)的SQL
						int 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位置的sql
							if(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(){
										@Override
										public 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 block
												e.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 block
									e.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;
	}
}