解決幾百萬條以上數據分頁讓人蛋疼的 SQL2005, SQL2008最後一頁卡死,最後一頁查詢超時的源碼

轉載:http://www.cnblogs.com/jirigala/archive/2012/03/08/2385895.html

應該很多人也遇到過這個問題,大概在2年前我也遇到過標題中的問題,當時研究了幾天很是糾結沒能徹底解決問題,後來也找了很多方法沒能解決問題。最近又遇到這個問題,實在是不解決也不行了,冷靜的想了想,完善了一下分頁查詢的方法,現在把代碼貼上,給大家參考,若有什麼漏洞,請及時聯繫吉日嘎拉,有錯我會積極修正。希望不要重複浪費生命,直接拿過去用就可以了,在通用權限管理系統組件裏也用了這個方法在進行分頁。

   最近維護一個每天有10萬多IP訪問的網站,也是用了這個分頁存儲過程,分頁效率還可以,最後一頁沒在出現卡死狀態,若有問題及時聯繫作者QQ:252056973,歡迎大家交流分享。當系統有少數幾個用戶實用時問題也不嚴重,但是系統每時每刻都有很多人訪問時那就鬧心了,很容易產生網站效率極低的,訪問量嚴重下降的趨勢。

   最後一頁分頁一卡死,整個網站的性能都會非常明顯的下降,不知道爲啥,微軟有這個BUG一直沒處理好。希望SQL2012裏不要有這個問題就好了

 

-- =============================================
-- Author:        吉日嘎拉
-- Create date: 2012年02月23日
-- Description:    2012年02月23日編碼規範化
-- =============================================
ALTER PROCEDURE [dbo].[GetRecordByPage] 
    @TableName          VARCHAR(4000),           -- 表名
    @SelectField        VARCHAR(4000),           -- 要顯示的字段名(不要加select)
    @WhereConditional   VARCHAR(4000),           -- 查詢條件(注意: 不要加 where)
    @SortExpression     VARCHAR(255),            -- 排序索引字段名
    @PageSize           INT = 20,                -- 頁大小
    @PageIndex          INT = 1,                 -- 頁碼
    @RecordCount        INT OUTPUT,              -- 返回記錄總數
    @SortDire           VARCHAR(5) = 'DESC'      -- 設置排序類型, 非 0 值則降序
AS
BEGIN

    DECLARE @commandText VARCHAR(8000)      -- 主語句
    DECLARE @TopN INT                         -- 獲取前幾條記錄
    DECLARE @PageCount INT                     -- 總共會是幾頁
    DECLARE @TopLimit INT                     -- 獲取多少條記錄
    DECLARE @SQLRowCount NVARCHAR(4000)     -- 用於查詢記錄總數的語句
    DECLARE @SQLOrder VARCHAR(400)          -- 排序類型
    DECLARE @SQLTemp VARCHAR(4000)          -- 臨時變量

    SET @SortExpression = LTRIM(RTRIM(@SortExpression))
    SET @SortDire = UPPER(LTRIM(RTRIM(@SortDire)))
    
    -- 這裏是計算整體記錄行數
    IF @RecordCount IS NULL
    BEGIN
        IF @WhereConditional != ''
        BEGIN
          SET @SQLRowCount = 'SELECT @RecordCount=COUNT(1) FROM ' + @TableName + ' WHERE ' + @WhereConditional
        END
        ELSE
        BEGIN
          SET @SQLRowCount = 'SELECT @RecordCount=COUNT(1) FROM ' + @TableName
        END
    END

    -- SELECT @RecordCount=@@ROWCOUNT
    EXEC sp_executesql @SQLRowCount, N'@RecordCount INT OUT', @RecordCount out

    IF @RecordCount IS NULL
    BEGIN
       SET @RecordCount = 0
    END
    
    -- 這裏是控制頁數最多少
    SET @PageCount = @RecordCount / @PageSize + 1
    
    -- 這裏檢查當前頁的有效性
    IF (@PageIndex < 1)
    BEGIN
        SET @PageIndex = 1
    END
    
    -- 這裏限制最後一頁的有效性
    IF (@PageIndex > @PageCount)
    BEGIN
        SET @PageIndex = @PageCount
    END

    IF @SortDire != 'ASC'
    BEGIN
        SET @SQLTemp = '<(SELECT MIN'
        SET @SQLOrder = ' ORDER BY ' + @SortExpression + ' DESC'
    END
    ELSE
    BEGIN
        set @SQLTemp = '>(SELECT MAX'
        set @SQLOrder = ' ORDER BY ' + @SortExpression + ' ASC'
    END
    
    -- 這裏是調試信息
    -- SELECT @SQLOrder

    -- 獲取幾條數據? 吉日嘎拉 2010-11-02 更新
    SET @TopN = @RecordCount - @PageSize * (@PageIndex - 1)
    IF @TopN > @PageSize
    BEGIN
        SET @TopN = @PageSize
    END

    SET @TopLimit = @PageSize * (@PageIndex - 1)
    IF @TopLimit > @RecordCount
    BEGIN
        SET @TopLimit = @RecordCount
    END

    SET @commandText = 'SELECT TOP ' + STR(@TopN) + ' ' + @SelectField + ' FROM '
        + @TableName + ' WHERE ' + @SortExpression + @SQLTemp + '('
        + RIGHT(@SortExpression, LEN(@SortExpression) - CHARINDEX('.', @SortExpression)) + ') FROM (SELECT TOP ' + STR(@TopLimit)
        + ' ' + @SortExpression + ' FROM ' + @TableName  + @SQLOrder + ') AS TableTemp)'
        + @SQLOrder

    IF @WhereConditional != ''
        SET @commandText = 'SELECT TOP ' + STR(@TopN) + ' ' + @SelectField + ' FROM '
            + @TableName + ' WHERE ' + @SortExpression + @SQLTemp + '('
            + RIGHT(@SortExpression, LEN(@SortExpression) - CHARINDEX('.',@SortExpression)) + ') FROM (SELECT TOP ' + STR(@TopLimit)
            + ' ' + @SortExpression + ' FROM ' + @TableName + ' WHERE ' + @WhereConditional + ' '
            + @SQLOrder + ') AS TableTemp) AND ' + @WhereConditional + ' ' + @SQLOrder

    IF @PageIndex = 1
    BEGIN
        -- 第一頁的顯示效率提高
        SET @SQLTemp = ''
        IF @WhereConditional != ''
            SET @SQLTemp = ' WHERE ' + @WhereConditional

        SET @commandText = 'SELECT TOP ' + STR(@TopN) + ' ' + @SelectField 
                          + ' FROM ' + @TableName + @SQLTemp + ' ' + @SQLOrder
    END
    ELSE
    BEGIN    
        -- 解決大數據最有一頁卡死的問題
        IF @PageIndex = @PageCount
        BEGIN
            IF @SortDire = 'ASC'
            BEGIN
                SET @SQLOrder = ' ORDER BY ' + @SortExpression + ' DESC'
            END
            ELSE
            BEGIN
                SET @SQLOrder = ' ORDER BY ' + @SortExpression + ' ASC'
            END
        
            SET @SQLTemp = ''
            IF @WhereConditional != ''
                SET @SQLTemp = ' WHERE ' + @WhereConditional
                
            SET @commandText = 'SELECT TOP ' + STR(@TopN) + ' ' + @SelectField 
                              + ' FROM ' + @TableName + @SQLTemp + ' ' + @SQLOrder
            
            SET @commandText = 'SELECT ' + @SelectField
                              + ' FROM (' + @commandText + ') AS TableTemp ORDER BY ' + @SortExpression + ' ' + @SortDire
        END
    END
    
    EXEC (@commandText)
    
    -- 這個是調試程序用的
    -- SELECT @commandText
    
END


 

發佈了24 篇原創文章 · 獲贊 9 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章