qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          幾種常見SQL分頁方式效率比較

           分頁很重要,面試會遇到。不妨再回顧總結一下。

            1、創建測試環境,(插入100萬條數據大概耗時5分鐘)。

          createdatabaseDBTest
          useDBTest

          --創建測試表
          createtablepagetest
          (
          idintidentity(1,1)notnull,
          col01intnull,
          col02nvarchar(50)null,
          col03datetimenull
          )

          --1萬記錄集
          declare@iint
          set@i=0
          while(@i<10000)
          begin
          insertintopagetestselectcast(floor(rand()*10000)asint),left(newid(),10),getdate()
          set@i=@i+1
          end

            2、幾種典型的分頁sql,下面例子是每頁50條,198*50=9900,取第199頁數據。

          --寫法1,not in/top
          selecttop50*frompagetest
          whereidnotin(selecttop9900idfrompagetestorderbyid)
          orderbyid




          --寫法2,not exists
          selecttop50*frompagetest
          wherenotexists
          (select1from(selecttop9900idfrompagetestorderbyid)awherea.id=pagetest.id)
          orderbyid

          --寫法3,max/top
          selecttop50*frompagetest
          whereid>(selectmax(id)from(selecttop9900idfrompagetestorderbyid)a)
          orderbyid

          --寫法4,row_number()
          selecttop50*from
          (selectrow_number()over(orderbyid)rownumber,*frompagetest)a
          whererownumber>9900

          select*from
          (selectrow_number()over(orderbyid)rownumber,*frompagetest)a
          whererownumber>9900andrownumber<9951

          select*from
          (selectrow_number()over(orderbyid)rownumber,*frompagetest)a
          whererownumberbetween9901and9950

          --寫法5,在csdn上一帖子看到的,row_number() 變體,不基于已有字段產生記錄序號,先按條件篩選以及排好序,再在結果集上給一常量列用于產生記錄序號
          select*
          from(
          selectrow_number()over(orderbytempColumn)rownumber,*
          from(selecttop9950tempColumn=0,*frompagetestwhere1=1orderbyid)a
          )b
          whererownumber>9900

            3、分別在1萬,10萬(取1990頁),100(取19900頁)記錄集下測試。

            測試sql:

          declare @begin_date datetime
          declare @end_date datetime
          select @begin_date = getdate()

          <.....YOUR CODE.....>

          select @end_date = getdate()
          select datediff(ms,@begin_date,@end_date) as '毫秒'

            1萬:基本感覺不到差異。

            10萬:

            100萬:

            4、結論:

            1)max/top,ROW_NUMBER()都是比較不錯的分頁方法。相比ROW_NUMBER()只支持sql2005及以上版本,max/top有更好的可移植性,能同時適用于sql2000,access。

            2)not exists感覺是要比not in效率高一點點。

            3)ROW_NUMBER()的3種不同寫法效率看起來差不多。

            4)ROW_NUMBER() 的變體基于我這個測試效率實在不好。

           PS:上面的分頁排序都是基于自增字段id。測試環境還提供了int,nvarchar,datetime類型字段,也可以試試。不過對于非主鍵沒索引的大數據量排序效率應該是很不理想的。

            5、簡單將ROWNUMBER,max/top的方式封裝到存儲過程。

            ROWNUMBER():

          create proc [dbo].[spSqlPageByRownumber]
          @tbName varchar(255), --表名
          @tbFields varchar(1000), --返回字段
          @PageSize int, --頁尺寸
          @PageIndex int, --頁碼
          @strWhere varchar(1000), --查詢條件
          @StrOrder varchar(255), --排序條件
          @Total int output --返回總記錄數
          as
          declare @strSql varchar(5000) --主語句
          declare @strSqlCount nvarchar(500)--查詢記錄總數主語句

          --------------總記錄數---------------
          if @strWhere !=''
          begin
          set @strSqlCount='Select @TotalCout=count(*) from ' + @tbName + ' where '+ @strWhere
          end
          else
          begin
          set @strSqlCount='Select @TotalCout=count(*) from ' + @tbName
          end
          --------------分頁------------
          if @PageIndex <= 0
          begin
          set @PageIndex = 1
          end

          set @strSql='Select * from (Select row_number() over('+@strOrder+') rowId,'+ @tbFields
          +' from ' + @tbName + ' where 1=1 ' + @strWhere+' ) tb where tb.rowId >'+str((@PageIndex-1)*@PageSize)
          +' and tb.rowId <= ' +str(@PageIndex*@PageSize)

          exec sp_executesql @strSqlCount,N'@TotalCout int output',@Total output
          exec(@strSql)

            Max/top:(簡單寫了下,需要滿足主鍵字段名稱就是"id")

          create proc [dbo].[spSqlPageByMaxTop]
          @tbName varchar(255), --表名
          @tbFields varchar(1000), --返回字段
          @PageSize int, --頁尺寸
          @PageIndex int, --頁碼
          @strWhere varchar(1000), --查詢條件
          @StrOrder varchar(255), --排序條件
          @Total int output --返回總記錄數
          as
          declare @strSql varchar(5000) --主語句
          declare @strSqlCount nvarchar(500)--查詢記錄總數主語句

          --------------總記錄數---------------
          if @strWhere !=''
          begin
          set @strSqlCount='Select @TotalCout=count(*) from ' + @tbName + ' where '+ @strWhere
          end
          else
          begin
          set @strSqlCount='Select @TotalCout=count(*) from ' + @tbName
          end
          --------------分頁------------
          if @PageIndex <= 0
          begin
          set @PageIndex = 1
          end

          set @strSql='select top '+str(@PageSize)+' * from ' + @tbName + '
          where id>(select max(id) from (select top
          '+str((@PageIndex-1)*@PageSize)+' id from ' + @tbName + ''+@strOrder+')a)
          '+@strOrder+''

          exec sp_executesql @strSqlCount,N'@TotalCout int output',@Total output
          exec(@strSql)

            調用:

          declare @count int
          --exec [dbo].[spSqlPageByRownumber]'pagetest','*',50,20,'','order by id asc',@count output
          exec [dbo].[spSqlPageByMaxTop]'pagetest','*',50,20,'','order by id asc',@count output
          select @count

          posted on 2011-11-09 16:42 順其自然EVO 閱讀(258) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2011年11月>
          303112345
          6789101112
          13141516171819
          20212223242526
          27282930123
          45678910

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 镇康县| 新兴县| 外汇| 延川县| 安陆市| 邹城市| 察隅县| 永安市| 榆中县| 文登市| 普兰县| 辽阳县| 弋阳县| 于都县| 祁东县| 申扎县| 古蔺县| 巴彦淖尔市| 凤翔县| 丽江市| 德州市| 吉安县| 乐东| 日喀则市| 凤翔县| 余干县| 大埔区| 巴马| 夏邑县| 天镇县| 永顺县| 根河市| 嘉禾县| 女性| 浪卡子县| 和顺县| 灯塔市| 逊克县| 龙泉市| 贞丰县| 灌南县|