Sql Server 資料分頁

來源:互聯網
上載者:User

標籤:des   blog   http   使用   os   strong   資料   art   

1.引言

在列表查詢時由於資料量非常多,一次性查出來會非常慢,就算一次查出來了,也不能一次性顯示給用戶端,所以要把資料進行分批查詢出來,每頁顯示一定量的資料,這就是資料要分頁。

2.常用的資料分頁方法

我們經常會碰到要取n到m條記錄,就是有分頁思想,下面羅列一下一般的方法。

我本地的一張表 tbl_FlightsDetail,有300多W記錄,主鍵 FlightsDetailID(Guid),要求按照FlightsDetailID排序 取 3000001 到3000010 之間的10條記錄,也是百萬級。

方法1 定位法 (利用ID大於多少)

語句形式:

select top 10 * from tbl_FlightsDetail where FlightsDetailID>(       select max(FlightsDetailID) from (               select top 3000000 FlightsDetailID from tbl_FlightsDetail order by FlightsDetailID       ) as t) order by FlightsDetailID

執行計畫:

先查出 top 300000,再彙總取這個集合中最大的Id1,再過濾 id大於id1的集合(中使用到索引),再取top 10 條。

 

方法2 (利用Not In)


語句形式:

select top 10* from tbl_FlightsDetail where FlightsDetailID not in (       select top 3000000 FlightsDetailID from tbl_FlightsDetail order by FlightsDetailID) order by FlightsDetailID

執行計畫:

和方法一類似,只是過濾where條件不一樣,這裡用到的是not in,中沒有用到索引,耗時8秒。如果 FlightsDetailID不是索引的話,方法1和該方法將差不多。

 

方法3 (利用顛顛倒倒top)

語句形式:

select top 10* from (       select top 3000010* from tbl_FlightsDetail order by FlightsDetailID) as t  order by t.FlightsDetailID desc

執行計畫:

先取 前面3000010條記錄,再倒序,這時再取前面10條即是300001 到300010條記錄,沒有用到索引,耗時11秒

 

方法4 (ROW_NUMBER()函數)

語句形式:

select * from (       select *,ROW_NUMBER() OVER (ORDER BY FlightsDetailID) as rank from tbl_FlightsDetail)  as t where t.rank between 3000001 and 3000010

 執行計畫:

Sql 2005版本或以上支援,也沒用到索引,耗時2秒,速度還不錯。

方法5 (利用IN)

此方法是由 金色海洋(jyk)陽光男孩 回複的,飛常感謝,語句形式:

select top 10 * from tbl_FlightsDetail  where FlightsDetailID in(        select top 10 FlightsDetailID from(                select top 3000010 FlightsDetailID from tbl_FlightsDetail order by FlightsDetailID       ) as t order by t.FlightsDetailID desc ) order by FlightsDetailID

執行計畫:

多次執行之後一般維持在4秒左右,用到索引,非常不錯,計劃圖還很長,只截取部分,可能是繞的多一點。

3.千萬級分頁預存程序

大家百度一下這個標題立馬會出現很多相關資訊,都大同小異,我自己拷貝的一個,應項目的需要,修改了一個排序的bug以及添加了返回總記錄數,如下:

SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGO--分頁預存程序  CREATE PROCEDURE [dbo].[sp_Paging] ( @Tables nvarchar(1000),                --表名/視圖名@PrimaryKey nvarchar(100),             --主鍵@Sort nvarchar(200) = NULL,            --排序欄位(不帶order by)@pageindex int = 1,                    --當前頁碼@PageSize int = 10,                    --每頁記錄數@Fields nvarchar(1000) = N‘*‘,         --輸出欄位@Filter nvarchar(1000) = NULL,         --where過濾條件(不帶where)@Group nvarchar(1000) = NULL,          --Group語句(不帶Group By)@TotalCount int OUTPUT                 --總記錄數) AS   DECLARE @SortTable nvarchar(100) DECLARE @SortName nvarchar(100) DECLARE @strSortColumn nvarchar(200) DECLARE @operator char(2) DECLARE @type nvarchar(100) DECLARE @prec int --設定排序語句IF @Sort IS NULL OR @Sort = ‘‘        SET @Sort = @PrimaryKey      IF CHARINDEX(‘DESC‘,@Sort)>0   BEGIN             SET @strSortColumn = REPLACE(@Sort, ‘DESC‘, ‘‘)             SET @operator = ‘<=‘     END ELSE     BEGIN                    SET @strSortColumn = REPLACE(@Sort, ‘ASC‘, ‘‘)                    SET @operator = ‘>=‘     END IF CHARINDEX(‘.‘, @strSortColumn) > 0     BEGIN             SET @SortTable = SUBSTRING(@strSortColumn, 0, CHARINDEX(‘.‘,@strSortColumn))    SET @SortName = SUBSTRING(@strSortColumn, CHARINDEX(‘.‘,@strSortColumn) + 1, LEN(@strSortColumn))     END ELSE     BEGIN             SET @SortTable = @Tables             SET @SortName = @strSortColumn  END --設定排序欄位類型和精度 SELECT @type=t.name, @prec=c.prec FROM sysobjects o        JOIN syscolumns c on o.id=c.id        JOIN systypes t on c.xusertype=t.xusertype WHERE o.name = @SortTable AND c.name = @SortName        IF CHARINDEX(‘char‘, @type) > 0       SET @type = @type + ‘(‘ + CAST(@prec AS varchar) + ‘)‘   DECLARE @strPageSize nvarchar(50) DECLARE @strStartRow nvarchar(50) DECLARE @strFilter nvarchar(1000) DECLARE @strSimpleFilter nvarchar(1000) DECLARE @strGroup nvarchar(1000)   IF @pageindex <1        SET @pageindex = 1  SET @strPageSize = CAST(@PageSize AS nvarchar(50)) --設定開始分頁記錄數 SET @strStartRow = CAST(((@pageindex - 1)*@PageSize + 1) AS nvarchar(50))  --篩選以及分組語句IF @Filter IS NOT NULL AND @Filter != ‘‘     BEGIN             SET @strFilter = ‘ WHERE ‘ + @Filter + ‘ ‘     SET @strSimpleFilter = ‘ AND ‘ + @Filter + ‘ ‘ END ELSE     BEGIN             SET @strSimpleFilter = ‘‘             SET @strFilter = ‘‘     END IF @Group IS NOT NULL AND @Group != ‘‘     SET @strGroup = ‘ GROUP BY ‘ --計算總記錄數DECLARE @TotalCountSql nvarchar(1000)SET @TotalCountSql=N‘SELECT @TotalCount=COUNT(*)‘ +N‘ FROM ‘ + @Tables + @strFilterEXEC sp_executesql @TotalCountSql,N‘@TotalCount int OUTPUT‘,@TotalCount OUTPUT--執行查詢語句    EXEC(‘DECLARE @SortColumn ‘ + @type + ‘SET ROWCOUNT ‘ + @strStartRow + ‘SELECT @SortColumn=‘ + @strSortColumn + ‘ FROM ‘ + @Tables + @strFilter + ‘ ‘ + @strGroup + ‘ ORDER BY ‘ + @Sort + ‘SET ROWCOUNT ‘ + @strPageSize + ‘SELECT ‘ + @Fields + ‘ FROM ‘ + @Tables + ‘ WHERE ‘ + @strSortColumn + @operator + ‘ @SortColumn ‘ + @strSimpleFilter + ‘ ‘ + @strGroup + ‘ ORDER BY ‘ + @Sort + ‘‘)

 現在我們來測試一下:

DECLARE    @return_value int,        @TotalCount intEXEC    @return_value = [dbo].[sp_Paging]        @Tables = N‘tbl_FlightsDetail‘,        @PrimaryKey = N‘FlightsDetailID‘,        @Sort = N‘FlightsDetailID‘,        @pageindex = 299999,        @PageSize = 10,        @Fields = ‘*‘,        @Filter = NULL,        @Group = NULL,        @TotalCount = @TotalCount OUTPUTSELECT    @TotalCount as N‘@TotalCount‘SELECT    ‘Return Value‘ = @return_value

執行計畫:

看時間的確是快,執行計畫顯示4個查詢

查詢1,是利用系統資料表擷取排序欄位、類型和精度,這個很快,全是索引。

查詢2,返回總記錄數,第一次會慢點,後面就很快了。

查詢3 和查詢4(用到索引) 才是我們要分頁取的資料,查詢3 是排序,取一個最大的值賦給變數,查詢4是大於這個變數的值 取資料,直接看sql語句,把上面的exec動態語句改成如下:

DECLARE @SortColumn varchar(40)--即 top 3000001,取出最大的 id覆蓋@SortColumn SET ROWCOUNT  3000001SELECT @SortColumn= FlightsDetailID  FROM tbl_FlightsDetail ORDER BY FlightsDetailID  --即 top 10SET ROWCOUNT 10SELECT *  FROM  tbl_FlightsDetail  WHERE FlightsDetailID   >= @SortColumn  ORDER BY  FlightsDetailID   

你會發現,原來它跟我們標題2 常用的資料分頁方法 中的 方法1 定位 類似,原來奧秘在這。

4.小結

還有一些用遊標、表變數的那個效能差不作考慮。分頁預存程序看起來挺複雜的,語句多,其實都在判斷,在左組裝,右組裝,最終組裝成類似 標題2中常用的分頁方法中的 的一種語句,掌握了常用的資料分頁方法,大家就可以自己寫了,當然還有其它的方法,大家可以分享出來。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.