中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

sqlserver2005的分頁優化

發布時間:2021-09-15 15:16:56 來源:億速云 閱讀:145 作者:chen 欄目:數據庫

這篇文章主要介紹“sqlserver2005的分頁優化”,在日常操作中,相信很多人在sqlserver2005的分頁優化問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”sqlserver2005的分頁優化”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!


一、hibernate分頁 hibernate對MsSql的偽分頁
分頁是web項目中比不可少的一個功能,數據量大的時候不能全部展示必然要用到分頁技術。相信大家對hibernate中的分頁都不陌生:
Java代碼 
public Query setMaxResults(int maxResults);  
public Query setFirstResult(int firstResult); 
Java代碼 
public Query setMaxResults(int maxResults); 
public Query setFirstResult(int firstResult); 

只要調用了這兩個方法并設置好參數,hibernate自動分頁完全屏蔽了底層分頁技術,這也是眾多開發者喜歡hibernate的原因之一。
項目開發中遇到一個奇怪的問題。數據庫采用的是Sql Server 2005,也設置了上面兩個參數,可是每次發送到數據庫端的SQL語句都是select top ....語句。即便是查詢第10w條,也只有一個select top 語句,不免引起對hibernate實現sql server分頁的懷疑。hibernate針對不同數據庫實現的分頁方法封裝在對應數據庫的方言里,通過getLimitString方法轉化成對應數據庫的分頁算法
以常見的Mysql數據庫的方言MySQLDialect為例:
Java代碼 
public String getLimitString(String sql, boolean hasOffset) {  
        return new StringBuffer( sql.length() + 20 )  
                .append( sql )  
                .append( hasOffset ? " limit ?, ?" : " limit ?" )  
                .toString();  
    } 
Java代碼 
public String getLimitString(String sql, boolean hasOffset) { 
        return new StringBuffer( sql.length() + 20 ) 
                .append( sql ) 
                .append( hasOffset ? " limit ?, ?" : " limit ?" ) 
                .toString(); 
    } 

采用了大家熟悉的的limit進行分頁。
數據庫的方言Oracle9iDialect:
Java代碼 
StringBuffer pagingSelect = new StringBuffer( sql.length()+100 );  
        if (hasOffset) {  
            pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");  
        }  
        else {  
            pagingSelect.append("select * from ( ");  
        }  
        pagingSelect.append(sql);  
        if (hasOffset) {  
            pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?");  
        }  
        else {  
            pagingSelect.append(" ) where rownum <= ?");  
        } 
Java代碼 
StringBuffer pagingSelect = new StringBuffer( sql.length()+100 ); 
        if (hasOffset) { 
            pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( "); 
        } 
        else { 
            pagingSelect.append("select * from ( "); 
        } 
        pagingSelect.append(sql); 
        if (hasOffset) { 
            pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?"); 
        } 
        else { 
            pagingSelect.append(" ) where rownum <= ?"); 
        } 

利用Oracle的rownum 結合三層嵌套查詢完成分頁。這個三層是Oracle最經典高效的分頁算法。
可是針對Sql Server的方言SQLServerDialect:
Java代碼 
public String getLimitString(String querySelect, int offset, int limit) {  
        if ( offset > 0 ) {  
            throw new UnsupportedOperationException( "query result offset is not supported" );  
        }  
        return new StringBuffer( querySelect.length() + 8 )  
                .append( querySelect )  
                .insert( getAfterSelectInsertPoint( querySelect ), " top " + limit )  
                .toString();  
    } 
Java代碼 
public String getLimitString(String querySelect, int offset, int limit) { 
        if ( offset > 0 ) { 
            throw new UnsupportedOperationException( "query result offset is not supported" ); 
        } 
        return new StringBuffer( querySelect.length() + 8 ) 
                .append( querySelect ) 
                .insert( getAfterSelectInsertPoint( querySelect ), " top " + limit ) 
                .toString(); 
    } 

揉揉眼睛、再揉揉,沒錯,只出現了一個top語句。這就意味著如果查詢第10w頁的數據,需要把前10w頁數據全部提取出來。hibernate針對sql server的分頁是偽分頁,所以隨著數據量日益增加用戶抱怨系統速度慢,程序員抱怨hibernate性能低,dba抱怨開發人員sql功底太淺。
不知道hibernate開發組,出于什么目前或情況沒有真正提供sql server的分頁技術,那我們自己來實現。
方言類:
Java代碼 
public class SQLServer2005Dialect extends SQLServerDialect {  
 
    /** 
     *  
     * 是否需要綁定limit參數? 
     *  
     * 在SQL Server中使用top時不能使用參數表示top條數,而使用ROW_NUMBER()則需要提供limit參數 
     */ 
 
    private ThreadLocal<Boolean> supportsVariableLimit = new ThreadLocal<Boolean>();  
    public SQLServer2005Dialect() {  
        registerFunction("bitand", new BitAndFunction());  
        registerFunction("bitxor", new BitXorFunction());  
        registerFunction("bitor", new BitOrFunction());  
        setSupportsVariableLimit(false);  
    }  
 
    /** 
     *  
     * <p> 
     * 設置是否先綁定limit參數。 
     * </p> 
     *  
     * @param first 
     */ 
 
    private void setSupportsVariableLimit(boolean first) {  
        this.supportsVariableLimit.set(Boolean.valueOf(first));  
    }  
 
    /** 
     *  
     * <p> 
     * 獲取sql中select子句位置。 
     * </p> 
     *  
     * @param sql 
     *  
     * @return int 
     */ 
    protected static int getSqlAfterSelectInsertPoint(String sql) {  
        int selectIndex = sql.toLowerCase().indexOf("select");  
 
        int selectDistinctIndex = sql.toLowerCase().indexOf("select distinct");  
 
        return selectIndex + ((selectDistinctIndex == selectIndex) ? 15 : 6);  
    }  
 
    public boolean supportsLimitOffset() {  
        return true;  
    }  
 
    /* 
     * Hibernate在獲得Limit String(已添加了limit子句)后,如果此方法返回true, 
     *  
     * 則會添加額外的參數值(ROW_NUMBER()范圍)(策略可能是這樣:有offset設置兩個參數值,沒有設置一個參數值) 
     */ 
    public boolean supportsVariableLimit() {  
        return ((Boolean) this.supportsVariableLimit.get()).booleanValue();  
    }  
 
    public boolean useMaxForLimit() {  
        return true;  
    }  
    /** 
     * 首頁top,以后用ROW_NUMBER 
     */ 
    public String getLimitString(String query, int offset, int limit) {  
        setSupportsVariableLimit(offset > 0);  
 
        if (offset == 0) {  
            return new StringBuffer(query.length() + 8).append(query).insert(  
                    getSqlAfterSelectInsertPoint(query), " top " + limit)  
                    .toString();  
        }  
 
        return getLimitString(query, offset > 0);  
    }  
      
    public String getLimitString(String sql, boolean hasOffset) {  
        int orderByIndex = sql.toLowerCase().lastIndexOf("order by");  
 
        if (orderByIndex <= 0) {  
            throw new UnsupportedOperationException(  
                    "must specify 'order by' statement to support limit operation with offset in sql server 2005");  
        }  
 
        String sqlOrderBy = sql.substring(orderByIndex + 8);  
 
        String sqlRemoveOrderBy = sql.substring(0, orderByIndex);  
 
        int insertPoint = getSqlAfterSelectInsertPoint(sql);  
        return new StringBuffer(sql.length() + 100)  
                .append("with tempPagination as(")  
                .append(sqlRemoveOrderBy)  
                .insert(  
                        insertPoint + 23,  
                        " ROW_NUMBER() OVER(ORDER BY " + sqlOrderBy  
                                + ") as RowNumber,")  
                .append(  
                        ") select * from tempPagination where RowNumber>?  and RowNumber<=?")  
                .toString();  
    }  

Java代碼 
public class SQLServer2005Dialect extends SQLServerDialect { 
 
    /**
     * 
     * 是否需要綁定limit參數?
     * 
     * 在SQL Server中使用top時不能使用參數表示top條數,而使用ROW_NUMBER()則需要提供limit參數
     */ 
 
    private ThreadLocal<Boolean> supportsVariableLimit = new ThreadLocal<Boolean>(); 
    public SQLServer2005Dialect() { 
        registerFunction("bitand", new BitAndFunction()); 
        registerFunction("bitxor", new BitXorFunction()); 
        registerFunction("bitor", new BitOrFunction()); 
        setSupportsVariableLimit(false); 
    } 
 
    /**
     * 
     * <p>
     * 設置是否先綁定limit參數。
     * </p>
     * 
     * @param first
     */ 
 
    private void setSupportsVariableLimit(boolean first) { 
        this.supportsVariableLimit.set(Boolean.valueOf(first)); 
    } 
 
    /**
     * 
     * <p>
     * 獲取sql中select子句位置。
     * </p>
     * 
     * @param sql
     * 
     * @return int
     */ 
    protected static int getSqlAfterSelectInsertPoint(String sql) { 
        int selectIndex = sql.toLowerCase().indexOf("select"); 
 
        int selectDistinctIndex = sql.toLowerCase().indexOf("select distinct"); 
 
        return selectIndex + ((selectDistinctIndex == selectIndex) ? 15 : 6); 
    } 
 
    public boolean supportsLimitOffset() { 
        return true; 
    } 
 
    /*
     * Hibernate在獲得Limit String(已添加了limit子句)后,如果此方法返回true,
     * 
     * 則會添加額外的參數值(ROW_NUMBER()范圍)(策略可能是這樣:有offset設置兩個參數值,沒有設置一個參數值)
     */ 
    public boolean supportsVariableLimit() { 
        return ((Boolean) this.supportsVariableLimit.get()).booleanValue(); 
    } 
 
    public boolean useMaxForLimit() { 
        return true; 
    } 
    /**
     * 首頁top,以后用ROW_NUMBER
     */ 
    public String getLimitString(String query, int offset, int limit) { 
        setSupportsVariableLimit(offset > 0); 
 
        if (offset == 0) { 
            return new StringBuffer(query.length() + 8).append(query).insert( 
                    getSqlAfterSelectInsertPoint(query), " top " + limit) 
                    .toString(); 
        } 
 
        return getLimitString(query, offset > 0); 
    } 
     
    public String getLimitString(String sql, boolean hasOffset) { 
        int orderByIndex = sql.toLowerCase().lastIndexOf("order by"); 
 
        if (orderByIndex <= 0) { 
            throw new UnsupportedOperationException( 
                    "must specify 'order by' statement to support limit operation with offset in sql server 2005"); 
        } 
 
        String sqlOrderBy = sql.substring(orderByIndex + 8); 
 
        String sqlRemoveOrderBy = sql.substring(0, orderByIndex); 
 
        int insertPoint = getSqlAfterSelectInsertPoint(sql); 
        return new StringBuffer(sql.length() + 100) 
                .append("with tempPagination as(") 
                .append(sqlRemoveOrderBy) 
                .insert( 
                        insertPoint + 23, 
                        " ROW_NUMBER() OVER(ORDER BY " + sqlOrderBy 
                                + ") as RowNumber,") 
                .append( 
                        ") select * from tempPagination where RowNumber>?  and RowNumber<=?") 
                .toString(); 
    } 

函數:
Java代碼 
public class BitAndFunction implements SQLFunction {  
    public Type getReturnType(Type type, Mapping mapping) {  
        return Hibernate.INTEGER;  
    }  
 
    public boolean hasArguments() {  
        return true;  
    }  
 
    public boolean hasParenthesesIfNoArguments() {  
        return true;  
    }  
 
    public String render(List args, SessionFactoryImplementor factory)  
            throws QueryException {  
        if (args.size() != 2) {  
            throw new IllegalArgumentException(  
                    "BitAndFunction requires 2 arguments!");  
        }  
        return args.get(0).toString() + " & " + args.get(1).toString();  
    }  

Java代碼 
public class BitAndFunction implements SQLFunction { 
    public Type getReturnType(Type type, Mapping mapping) { 
        return Hibernate.INTEGER; 
    } 
 
    public boolean hasArguments() { 
        return true; 
    } 
 
    public boolean hasParenthesesIfNoArguments() { 
        return true; 
    } 
 
    public String render(List args, SessionFactoryImplementor factory) 
            throws QueryException { 
        if (args.size() != 2) { 
            throw new IllegalArgumentException( 
                    "BitAndFunction requires 2 arguments!"); 
        } 
        return args.get(0).toString() + " & " + args.get(1).toString(); 
    } 

 
Java代碼 
public class BitOrFunction implements SQLFunction {  
    public Type getReturnType(Type type, Mapping mapping) {  
        return Hibernate.INTEGER;  
    }  
    public boolean hasArguments() {  
        return true;  
    }  
    public boolean hasParenthesesIfNoArguments() {  
        return true;  
    }  
    public String render(List args, SessionFactoryImplementor factory)  
            throws QueryException {  
        if (args.size() != 2) {  
            throw new IllegalArgumentException(  
                    "BitOrFunction requires 2 arguments!");  
        }  
        return args.get(0).toString() + " | " + args.get(1).toString();  
    }  

Java代碼 
public class BitOrFunction implements SQLFunction { 
    public Type getReturnType(Type type, Mapping mapping) { 
        return Hibernate.INTEGER; 
    } 
    public boolean hasArguments() { 
        return true; 
    } 
    public boolean hasParenthesesIfNoArguments() { 
        return true; 
    } 
    public String render(List args, SessionFactoryImplementor factory) 
            throws QueryException { 
        if (args.size() != 2) { 
            throw new IllegalArgumentException( 
                    "BitOrFunction requires 2 arguments!"); 
        } 
        return args.get(0).toString() + " | " + args.get(1).toString(); 
    } 

 
Java代碼 
public Type getReturnType(Type type, Mapping mapping) {  
        return Hibernate.INTEGER;  
    }  
    public boolean hasArguments() {  
        return true;  
    }  
    public boolean hasParenthesesIfNoArguments() {  
        return true;  
    }  
    public String render(List args, SessionFactoryImplementor factory)  
            throws QueryException {  
        if (args.size() != 2) {  
            throw new IllegalArgumentException(  
                    "BitXorFunction requires 2 arguments!");  
        }  
        return args.get(0).toString() + " ^ " + args.get(1).toString();  
    } 


到此,關于“sqlserver2005的分頁優化”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

白水县| 东乌| 方城县| 台山市| 缙云县| 米泉市| 中方县| 皮山县| 诏安县| 卓尼县| 新建县| 岐山县| 汉沽区| 卫辉市| 济阳县| 云安县| 伊宁市| 得荣县| 酒泉市| 湟中县| 达日县| 临沧市| 汉川市| 五莲县| 通化县| 务川| 普安县| 东乡族自治县| 万山特区| 新郑市| 清水河县| 阿拉善左旗| 延寿县| 南漳县| 定襄县| 周口市| 江阴市| 灌阳县| 东丰县| 鄱阳县| 柳州市|