Sybase 大資料量(100W條)分頁 jdbc實現目前要求無排序
首次分頁大概為10秒左右。以後翻頁基本上是瞬間完成。要求是無排序情況下。
分析:sybase不提供分頁方法。top函式還不能放在子查詢語句中。使用hibernate分頁前幾頁和後幾頁沒問題,如果資料量大翻到30000頁時就記憶體溢位了。而且效率慢。
使用儲存過程分頁大資料量也不適合。效率低而且不支援併發。
由於 select top pageSize column1,column2,column3 from tableName where id > ?這種語句也相當快但如果資料列多會有大量流量產生。
select count(*) from table 這個語句比較慢100W條也得10秒
綜上所述,分三個步驟
1,把所資料總數取出來
如果每次都從資料庫取會浪費不必要的時間。所以第一次載入的時候使用快取儲存起來。
SQL:select count(*) from table
2,找到需呀資料的id
如果資料量比較大100W條,如果查詢第50W條速度也比較慢。所以第一次載入的時候需要快取,快取的內容為資料的id以及位置。
例如:100W條資料快取50個位置,每2W條一個 。那麼從100W條資料中找某一個id就相當於從2W條中找
SQL:select top pageSize+startNumber id from tableName where id > ?
3,把資料取出來
SQL:select top pageSize column1,column2,column3 from tableName where id >=?
/**
* 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;
int cacount = CacheUtil.getTotalSize(sql);//讀取總數快取
int total = 0;
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(" where ").append(id).append(">=").append(ids.get(0));
execsql = "select top "+pageSize+execsql.substring(execsql.toLowerCase().indexOf("select")+6);
}else{//有排序使用id=? or id=?
sbsql.append(" where (");
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 += sbsql.toString();
}else {
execsql = execsql.substring(0, execsql.toLowerCase().indexOf("where"))+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;
}
}
Reference:
http://www.tuicool.com/articles/ryIjIn
相關文章
- 大資料量的報表如何快速分頁呈現?大資料
- access資料庫大資料量分頁的問題資料庫大資料
- 請教大資料量查詢怎麼分頁查詢?資料量大概有7,8億條。謝謝大資料
- mysql大資料量分頁查詢方法及其優化MySql大資料優化
- DataTables自定義分頁條數實現
- 實現小資料量和海量資料的通用分頁顯示儲存過程儲存過程
- 報表連 hive,資料量比較大,怎麼分頁查詢?Hive
- 千萬條資料,Stack Overflow 是如何實現快速分頁的?
- Ajax 實現無重新整理分頁
- PbootCMS實現數字條分頁樣式效果boot
- sql 資料庫 龐大資料量 需要分表SQL資料庫大資料
- oracle外部表實現大資料量的Excel匯入Oracle大資料Excel
- 資料量大了一定要分表,分庫分表元件Sharding-JDBC入門與專案實戰元件JDBC
- JDBC 大資料集分頁 ,大資料讀寫及事務的隔離級別JDBC大資料
- 記一次sybase12.5 之com.sybase.jdbc3.jdbc.SybSQLExceptionJDBCSQLException
- Sybase15驅動包的問題com.sybase.jdbc3.jdbc.SybDriverJDBC
- MySQL實現分組排序MySql排序
- 資料量很大,分頁查詢很慢,該怎麼優化?優化
- Mysql生成100w條測試資料MySql
- 大資料量處理實踐方案整理大資料
- JDBC【資料庫連線池、DbUtils框架、分頁】JDBC資料庫框架
- elementUI實現分頁UI
- 分頁的實現
- laravel實現100w大量資料插入資料庫Laravel資料庫
- MySQL 百萬級資料量分頁查詢方法及其最佳化MySql
- 加快排序與分頁排序
- Python 大資料量文字檔案高效解析方案程式碼實現Python大資料
- java web實現分頁顯示資料JavaWeb
- oracle 大資料量資料插入Oracle大資料
- 分頁功能的實現
- Java Web 分頁實現JavaWeb
- Mybatis分頁實現流程MyBatis
- 報表連 MongoDB,資料量大報表慢,怎麼做分頁?MongoDB
- redis實現像關係型資料庫一樣按條件高效查詢分頁Redis資料庫
- python實現資料分頁小練習Python
- 常見資料庫的分頁實現方案資料庫
- oracle資料庫用sql實現快速分頁Oracle資料庫SQL
- SpringBoot整合Jpa對資料進行排序、分頁、條件查詢和過濾Spring Boot排序