大資料量分頁儲存過程效率測試
我首先寫了五個常用儲存過程:
1,利用select top 和select not in進行分頁,具體程式碼如下:
CREATE PROCEDURE Proc_paged_with_notin --利用select top and select not in
(@pageIndex INT,--頁索引
@pageSize INT --每頁記錄數
)
AS
BEGIN
SET nocount ON;
DECLARE @timediff DATETIME --耗時
DECLARE @sql NVARCHAR(500)
SELECT @timediff = Getdate()
SET @sql='select top ' + Str(@pageSize)
+ ' * from tb_TestTable where(ID not in(select top '
+ Str(@pageSize*@pageIndex)
+ ' id from tb_TestTable order by ID ASC)) order by ID'
EXECUTE(@sql)
--因select top後不支技直接接引數,所以寫成了字串@sql
SELECT Datediff(ms, @timediff, Getdate()) AS 耗時
SET nocount OFF;
END
2,利用select top 和 select max(列鍵)
CREATE PROCEDURE Proc_paged_with_selectmax
--利用select top and select max(列)
(@pageIndex INT,--頁索引
@pageSize INT --頁記錄數
)
AS
BEGIN
SET nocount ON;
DECLARE @timediff DATETIME
DECLARE @sql NVARCHAR(500)
SELECT @timediff = Getdate()
SET @sql='select top ' + Str(@pageSize)
+
' * From tb_TestTable where(ID>(select max(id) From (select top '
+ Str(@pageSize*@pageIndex)
+ ' id From tb_TestTable order by ID) as TempTable)) order by ID'
EXECUTE(@sql)
SELECT Datediff(ms, @timediff, Getdate()) AS 耗時
SET nocount OFF;
END
3,利用select top和中間變數–此方法因網上有人說效果最佳,所以貼出來一同測試
CREATE PROCEDURE Proc_paged_with_midvar --利用ID>最大ID值和中間變數
(@pageIndex INT,
@pageSize INT)
AS
DECLARE @count INT
DECLARE @ID INT
DECLARE @timediff DATETIME
DECLARE @sql NVARCHAR(500)
BEGIN
SET nocount ON;
SELECT @count = 0,
@ID = 0,
@timediff = Getdate()
SELECT @count = @count + 1,
@ID = CASE
WHEN @count <= @pageSize * @pageIndex THEN id
ELSE @ID
END
FROM tb_testtable
ORDER BY id
SET @sql='select top ' + Str(@pageSize)
+ ' * from tb_testTable where ID>' + Str(@ID)
EXECUTE(@sql)
SELECT Datediff(ms, @timediff, Getdate()) AS 耗時
SET nocount OFF;
END
4,利用Row_number() 此方法為sql server 2005中新的方法,利用Row_number()給資料行加上索引
CREATE PROCEDURE Proc_paged_with_rownumber --利用SQL 2005中的Row_number()
(@pageIndex INT,
@pageSize INT)
AS
DECLARE @timediff DATETIME
BEGIN
SET nocount ON;
SELECT @timediff = Getdate()
SELECT *
FROM (SELECT *,
Row_number()
OVER(
ORDER BY id ASC) AS IDRank
FROM tb_testtable) AS IDWithRowNumber
WHERE idrank > @pageSize * @pageIndex
AND idrank < @pageSize * ( @pageIndex + 1 )
SELECT Datediff(ms, @timediff, Getdate()) AS 耗時
SET nocount OFF;
END
5,利用臨時表及Row_number
CREATE PROCEDURE Proc_cte --利用臨時表及Row_number
(@pageIndex INT,--頁索引
@pageSize INT --頁記錄數
)
AS
SET nocount ON;
DECLARE @ctestr NVARCHAR(400)
DECLARE @strSql NVARCHAR(400)
DECLARE @datediff DATETIME
BEGIN
SELECT @datediff = Getdate()
SET @ctestr='with Table_CTE as (select ceiling((Row_number() over(order by ID ASC))/'
+ Str(@pageSize)
+ ') as page_num,* from tb_TestTable)';
SET @[email protected]
+ ' select * From Table_CTE where page_num='
+ Str(@pageIndex)
END
BEGIN
EXECUTE Sp_executesql
@strSql
SELECT Datediff(ms, @datediff, Getdate())
SET nocount OFF;
END
OK,至此,儲存過程建立完畢,我們分別在每頁10條資料的情況下在第2頁,第1000頁,第10000頁,第100000頁,第199999頁進行測試,耗時單位:ms 每頁測試5次取其平均值
存過 第2頁耗時 第1000頁耗時 第10000頁耗時 第100000頁耗時 第199999頁耗時 效率排行
序號 | 存過 | 第2頁耗時 | 第1000頁耗時 | 第10000頁耗時 | 第100000頁耗時 | 第199999頁耗時 | 效率排行 |
---|---|---|---|---|---|---|---|
1 | 用not in | 0ms | 16ms | 47ms | 475ms | 953ms | 3 |
2 | 用select max | 5ms | 16ms | 35ms | 325ms | 623ms | 1 |
3 | 中間變數 | 966ms | 970ms | 960ms | 945ms | 933ms | 5 |
4 | row_number | 0ms | 0ms | 34ms | 365ms | 710ms | 2 |
4 | 臨時表 | 780ms | 796ms | 798ms | 780ms | 805ms | 4 |
測試結果顯示:select max >row_number>not in>臨時表>中間變數
於是我對效率最高的select max方法用2分法進行了擴充套件,程式碼取自網際網路,我修改了ASC排序時取不到值的BUG,測試結果:
2分法 156ms 156ms 180ms 470ms 156ms 1*
從測試結果來看,使用2分法確實可以提高效率並使效率更為穩定,我又增加了第159999頁的測試,用時僅296ms,效果相當的不錯!
下面是2分法使用select max的程式碼,已相當完善。
--/*----- 對資料進行了2分處理使查詢前半部分資料與查詢後半部分資料效能相同 -------*/
ALTER PROCEDURE Proc_paged_2part_selectmax (@tblName NVARCHAR(200),
----要顯示的表或多個表的連線
@fldName NVARCHAR(500) = '*',
----要顯示的欄位列表
@pageSize INT = 10,
----每頁顯示的記錄個數
@page INT = 1,
----要顯示那一頁的記錄
@fldSort NVARCHAR(200) = NULL,
----排序欄位列表或條件
@Sort BIT = 0,
----排序方法,0為升序,1為降序(如果是多欄位排列Sort指代最後一個排序欄位的排列順序(最後一個排序欄位不加排序標記)--程式傳參如:' SortA Asc,SortB Desc,SortC ')
@strCondition NVARCHAR(1000) = NULL,
----查詢條件,不需where
@ID NVARCHAR(150),
----主表的主鍵
@Dist BIT = 0,
----是否新增查詢欄位的 DISTINCT 預設0不新增/1新增
@pageCount INT = 1 output,
----查詢結果分頁後的總頁數
@Counts INT = 1 output
----查詢到的記錄數
)
AS
SET nocount ON
DECLARE @sqlTmp NVARCHAR(1000) ----存放動態生成的SQL語句
DECLARE @strTmp NVARCHAR(1000)
----存放取得查詢結果總數的查詢語句
DECLARE @strID NVARCHAR(1000)
----存放取得查詢開頭或結尾ID的查詢語句
DECLARE @strSortType NVARCHAR(10) ----資料排序規則A
DECLARE @strFSortType NVARCHAR(10) ----資料排序規則B
DECLARE @SqlSelect NVARCHAR(50)
----對含有DISTINCT的查詢進行SQL構造
DECLARE @SqlCounts NVARCHAR(50)
----對含有DISTINCT的總數查詢進行SQL構造
DECLARE @timediff DATETIME --耗時測試時間差
SELECT @timediff = Getdate()
IF @Dist = 0
BEGIN
SET @SqlSelect = 'select '
SET @SqlCounts = 'Count(*)'
END
ELSE
BEGIN
SET @SqlSelect = 'select distinct '
SET @SqlCounts = 'Count(DISTINCT ' + @ID + ')'
END
IF @Sort = 0
BEGIN
SET @strFSortType=' ASC '
SET @strSortType=' DESC '
END
ELSE
BEGIN
SET @strFSortType=' DESC '
SET @strSortType=' ASC '
END
--------生成查詢語句--------
--此處@strTmp為取得查詢結果數量的語句
IF @strCondition IS NULL
OR @strCondition = '' --沒有設定顯示條件
BEGIN
SET @sqlTmp = @fldName + ' From ' + @tblName
SET @strTmp = @SqlSelect + ' @Counts=' + @SqlCounts + ' FROM '
+ @tblName
SET @strID = ' From ' + @tblName
END
ELSE
BEGIN
SET @sqlTmp = + @fldName + 'From ' + @tblName + ' where (1>0) '
+ @strCondition
SET @strTmp = @SqlSelect + ' @Counts=' + @SqlCounts + ' FROM '
+ @tblName + ' where (1>0) ' + @strCondition
SET @strID = ' From ' + @tblName + ' where (1>0) '
+ @strCondition
END
----取得查詢結果總數量-----
EXEC Sp_executesql
@strTmp,
N'@Counts int out ',
@Counts out
DECLARE @tmpCounts INT
IF @Counts = 0
SET @tmpCounts = 1
ELSE
SET @tmpCounts = @Counts
--取得分頁總數
SET @pageCount=( @tmpCounts + @pageSize - 1 ) / @pageSize
/**//**//**//**當前頁大於總頁數 取最後一頁**/
IF @page > @pageCount
SET @page=@pageCount
--/*-----資料分頁2分處理-------*/
DECLARE @pageIndex INT --總數/頁大小
DECLARE @lastcount INT --總數%頁大小
SET @pageIndex = @tmpCounts / @pageSize
SET @lastcount = @tmpCounts%@pageSize
IF @lastcount > 0
SET @pageIndex = @pageIndex + 1
ELSE
SET @lastcount = @pagesize
--//***顯示分頁
IF @strCondition IS NULL
OR @strCondition = '' --沒有設定顯示條件
BEGIN
IF @pageIndex < 2
OR @page <= @pageIndex / 2 + @pageIndex % 2
--前半部分資料處理
BEGIN
IF @page = 1
SET @strTmp=@SqlSelect + ' top '
+ Cast(@pageSize AS VARCHAR(4)) + ' '
+ @fldName + ' from ' + @tblName + ' order by '
+ @fldSort + ' ' + @strFSortType
ELSE
BEGIN
IF @Sort = 1
BEGIN
SET @strTmp=@SqlSelect + ' top '
+ Cast(@pageSize AS VARCHAR(4)) + ' '
+ @fldName + ' from ' + @tblName +
' where '
+
@ID
+ ' <(select min(' + @ID + ') from (' +
@SqlSelect
+ ' top '
+ Cast(@pageSize*(@page-1) AS VARCHAR(20
))
+ ' ' + @ID + ' from ' + @tblName +
' order by '
+ @fldSort + ' ' + @strFSortType +
') AS TBMinID)'
+ ' order by ' + @fldSort + ' ' +
@strFSortType
END
ELSE
BEGIN
SET @strTmp=@SqlSelect + ' top '
+ Cast(@pageSize AS VARCHAR(4)) + ' '
+ @fldName + ' from ' + @tblName +
' where '
+
@ID
+ ' >(select max(' + @ID + ') from (' +
@SqlSelect
+ ' top '
+ Cast(@pageSize*(@page-1) AS VARCHAR(20
))
+ ' ' + @ID + ' from ' + @tblName +
' order by '
+ @fldSort + ' ' + @strFSortType +
') AS TBMinID)'
+ ' order by ' + @fldSort + ' ' +
@strFSortType
END
END
END
ELSE
BEGIN
SET @page = @pageIndex - @page + 1 --後半部分資料處理
IF @page <= 1 --最後一頁資料顯示
SET @strTmp=@SqlSelect + ' * from (' + @SqlSelect + ' top '
+ Cast(@lastcount AS VARCHAR(4)) + ' '
+ @fldName + ' from ' + @tblName + ' order by '
+ @fldSort + ' ' + @strSortType + ') AS TempTB'
+ ' order by ' + @fldSort + ' ' + @strFSortType
ELSE IF @Sort = 1
BEGIN
SET @strTmp=@SqlSelect + ' * from (' + @SqlSelect +
' top '
+ Cast(@pageSize AS VARCHAR(4)) + ' '
+ @fldName + ' from ' + @tblName + ' where ' +
@ID
+ ' >(select max(' + @ID + ') from(' +
@SqlSelect
+ ' top '
+ Cast(@pageSize*(@page-2)+@lastcount AS
VARCHAR(
20)
)
+ ' ' + @ID + ' from ' + @tblName +
' order by '
+ @fldSort + ' ' + @strSortType +
') AS TBMaxID)'
+ ' order by ' + @fldSort + ' ' + @strSortType
+ ') AS TempTB' + ' order by ' + @fldSort +
' '
+ @strFSortType
END
ELSE
BEGIN
SET @strTmp=@SqlSelect + ' * from (' + @SqlSelect +
' top '
+ Cast(@pageSize AS VARCHAR(4)) + ' '
+ @fldName + ' from ' + @tblName + ' where ' +
@ID
+ ' <(select min(' + @ID + ') from(' +
@SqlSelect
+ ' top '
+ Cast(@pageSize*(@page-2)+@lastcount AS
VARCHAR(
20)
)
+ ' ' + @ID + ' from ' + @tblName +
' order by '
+ @fldSort + ' ' + @strSortType +
') AS TBMaxID)'
+ ' order by ' + @fldSort + ' ' + @strSortType
+ ') AS TempTB' + ' order by ' + @fldSort +
' '
+ @strFSortType
END
END
END
ELSE --有查詢條件
BEGIN
IF @pageIndex < 2
OR @page <= @pageIndex / 2 + @pageIndex % 2
--前半部分資料處理
BEGIN
IF @page = 1
SET @strTmp=@SqlSelect + ' top '
+ Cast(@pageSize AS VARCHAR(4)) + ' '
+ @fldName + ' from ' + @tblName + ' where 1=1 '
+ @strCondition + ' order by ' + @fldSort + ' '
+ @strFSortType
ELSE IF( @Sort = 1 )
BEGIN
SET @strTmp=@SqlSelect + ' top '
+ Cast(@pageSize AS VARCHAR(4)) + ' '
+ @fldName + ' from ' + @tblName + ' where ' +
@ID
+ ' <(select min(' + @ID + ') from (' +
@SqlSelect
+ ' top '
+ Cast(@pageSize*(@page-1) AS VARCHAR(20))
+ ' ' + @ID + ' from ' + @tblName +
' where (1=1) '
+ @strCondition + ' order by ' + @fldSort +
' '
+ @strFSortType + ') AS TBMinID)' + ' '
+ @strCondition + ' order by ' + @fldSort +
' '
+ @strFSortType
END
ELSE
BEGIN
SET @strTmp=@SqlSelect + ' top '
+ Cast(@pageSize AS VARCHAR(4)) + ' '
+ @fldName + ' from ' + @tblName + ' where ' +
@ID
+ ' >(select max(' + @ID + ') from (' +
@SqlSelect
+ ' top '
+ Cast(@pageSize*(@page-1) AS VARCHAR(20))
+ ' ' + @ID + ' from ' + @tblName +
' where (1=1) '
+ @strCondition + ' order by ' + @fldSort +
' '
+ @strFSortType + ') AS TBMinID)' + ' '
+ @strCondition + ' order by ' + @fldSort +
' '
+ @strFSortType
END
END
ELSE
BEGIN
SET @page = @pageIndex - @page + 1 --後半部分資料處理
IF @page <= 1 --最後一頁資料顯示
SET @strTmp=@SqlSelect + ' * from (' + @SqlSelect + ' top '
+ Cast(@lastcount AS VARCHAR(4)) + ' '
+ @fldName + ' from ' + @tblName + ' where (1=1) '
+ @strCondition + ' order by ' + @fldSort + ' '
+ @strSortType + ') AS TempTB' + ' order by '
+ @fldSort + ' ' + @strFSortType
ELSE IF( @Sort = 1 )
SET @strTmp=@SqlSelect + ' * from (' + @SqlSelect + ' top '
+ Cast(@pageSize AS VARCHAR(4)) + ' '
+ @fldName + ' from ' + @tblName + ' where ' + @ID
+ ' >(select max(' + @ID + ') from(' + @SqlSelect
+ ' top '
+ Cast(@pageSize*(@page-2)+@lastcount AS VARCHAR(
20))
+ ' ' + @ID + ' from ' + @tblName +
' where (1=1) '
+ @strCondition + ' order by ' + @fldSort + ' '
+ @strSortType + ') AS TBMaxID)' + ' '
+ @strCondition + ' order by ' + @fldSort + ' '
+ @strSortType + ') AS TempTB' + ' order by '
+ @fldSort + ' ' + @strFSortType
ELSE
SET @strTmp=@SqlSelect + ' * from (' + @SqlSelect + ' top '
+ Cast(@pageSize AS VARCHAR(4)) + ' '
+ @fldName + ' from ' + @tblName + ' where ' + @ID
+ ' <(select min(' + @ID + ') from(' + @SqlSelect
+ ' top '
+ Cast(@pageSize*(@page-2)+@lastcount AS VARCHAR(
20))
+ ' ' + @ID + ' from ' + @tblName +
' where (1=1) '
+ @strCondition + ' order by ' + @fldSort + ' '
+ @strSortType + ') AS TBMaxID)' + ' '
+ @strCondition + ' order by ' + @fldSort + ' '
+ @strSortType + ') AS TempTB' + ' order by '
+ @fldSort + ' ' + @strFSortType
END
END
------返回查詢結果-----
EXEC Sp_executesql
@strTmp
SELECT Datediff(ms, @timediff, Getdate()) AS 耗時
--print @strTmp
SET nocount OFF
go
執行示例:
exec proc_paged_2part_selectMax 'tb_testTable','ID,userName,userPWD,userEmail',10,100000,'ID',0,null,'ID',0
這種測試只在單機進行,並且沒有在實際開發WEB專案中分頁測試,測試項也比較單一,所以不夠全面系統,但從其效率相比上,我們可以在資料庫分頁演算法上進行有效的控制。
相關推薦
大資料量分頁儲存過程效率測試
我首先寫了五個常用儲存過程: 1,利用select top 和select not in進行分頁,具體程式碼如下: CREATE PROCEDURE Proc_paged_with_notin --利用select top and select n
sql2000,千萬級大資料量分頁儲存過程效率測試附程式碼
在專案中,我們經常遇到或用到分頁,那麼在大資料量(百萬級以上)下,哪種分頁演算法效率最優呢?我們不妨用事實說話。 測試環境 硬體:CPU 酷睿雙核T5750 記憶體:2G 軟體:Windows server 2003 + Sql server 2005 OK
解決mongodb大資料量分頁查詢效率問題
最常見的分頁採用的是skip+limit這種組合方式,這種方式對付小資料倒也可以,但是對付上幾百上千萬的大資料,只能力不從心,skip如果跳過大量的資料會很慢,並且會越查越慢,針對這一情況,可以通過條件查詢+排序+限制返回記錄,即 邊查詢,邊排序,排序之後,抽取上一頁中的最後一條記錄,作為當前分
mongodb大資料量分頁查詢效率問題
最常見的分頁採用的是skip+limit這種組合方式,這種方式對付小資料倒也可以,但是對付上幾百上千萬的大資料,只能力不從心,skip如果跳過大量的資料會很慢,並且會越查越慢。 //程式碼大概看下意思就行了 const list = db.getCollection('se
MySQL大資料量分頁查詢方法及其優化 MySQL大資料量分頁查詢方法及其優化
MySQL大資料量分頁查詢方法及其優化 ---方法1: 直接使用資料庫提供的SQL語句---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N ---適應場景: 適用於資料量較少的情況(元組百/千級) --
MySQL大資料量分頁查詢方法及其優化 ---方法1: 直接使用資料庫提供的SQL語句 ---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N ---適
測試實驗 1. 直接用limit start, count分頁語句, 也是我程式中用的方法: select * from product limit start, count 當起始頁較小時,查詢沒有效能問題,我們分別看下從10, 100, 1000, 10000開始分頁的執行時間(每頁取20條), 如
mysql 大資料量分頁優化
假設有一個千萬量級的表,取1到10條資料; select * from table limit 0,10; select * from table limit 1000,10; 這兩條語句查詢時間應該在毫秒級完成; select * from table limit
MySQL大資料量分頁查詢方法及其優化
方法1: 直接使用資料庫提供的SQL語句 語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N 適應場景: 適用於資料量較少的情況(元組百/千級) 原因/缺點: 全表掃描,速度會很慢 且 有的資料庫結果集返回不穩定(如某次返回
SQL大資料量分頁效能優化
目前在進行web api只讀介面的改造,在改造過程中,發現改在後響應時間和之前區別不是很大,通過測試結果顯示在sql的分頁功能處找到原因,並對其進行優化,優化方案如下。測試內容此次執行時間對比採用平臺資金記錄最多的使用者 user_id 36062測試次數未5次 為避免索引
Displaytag使用與應用displaytag完成大資料量分頁顯示的例子
Display Tag Lib是一個標籤庫,用來處理jsp網頁上的Table,功能非常強,可以對的Table進行分頁、資料匯出、分組、對列排序等等,反正我在做專案時需要的功能它都給我提供了,而且使用起來非常的方便。能夠大大減少程式碼量。 介個是Display Tag
大資料量分頁優化--延遲查詢
延遲關聯 select * from it_area where name like '%東山%';+------+-----------+------+ | id | name | pid | +------+-----------+------+ |
MySQL大資料量分頁SQL語句優化
分頁程式原理很簡單,這裡就不多說了,本篇文章主要說的是在資料表記錄量比較大的情況下,如何將分頁SQL做到更優化,讓MySQL執行的更快的方法。 一般的情況下,我們的分頁SQL語句是這樣的:
【資料庫效能測試實戰】測試不同分頁儲存過程在10w,100w以及1000w資料量下面的表現
前言 資料庫的效能與每一行程式碼息息相關,所以,每次寫程式碼可以考慮一下在不同級別的資料量下面測試一下效能。 本文參考了: Postgresql生成大量測試資料 以及 準備測試用資料 此次測試我們將分別用10w,100w以及1000w級別的表來測試,下面先建立
mysql分頁儲存過程一步一步實現
1. CREATE DEFINER=`root`@`localhost` PROCEDURE `P_HoverTreePages`( IN `TableName` VARCHAR(200), IN `FieldList` VARCHAR(2000) , IN `Pr
Vs呼叫分頁儲存過程
/// <summary> /// 顯示+分頁+模糊查詢 /// </summary> &n
MSSQL資料庫分頁儲存過程
create procedure [dbo].[p_splitpage] @sql nvarchar(4000), @currentpage int=2, @pagesize int=10, @recordcount int=0 output, @pagecount int=0 out
分頁儲存過程
-- ============================================= -- Author: <Author,,Name> -- Create date: <Create Date,,> -- Description: &l
增刪改查分頁儲存過程
--建立資料庫 CREATE DATABASE PROCDB GO --使用資料庫 GO USE PROCDB GO --建立表供儲存過程的實現 CREATE TABLE STUDENTINFOS ( ID INT PRIMARY KEY IDENTITY, S_NAME NVARCHA
C# DataGridView分頁功能(SQL分頁儲存過程實現)
{ dtStaff.Clear(); SqlConnection conn = new SqlConnection(Param_Class.Param_DB.strConn); SqlDataAdapter Sda = new SqlDataA
分頁-儲存過程5種寫法 sqlserver分頁
在SQL Server資料庫操作中,我們常常會用到儲存過程對實現對查詢的資料的分頁處理,以方便瀏覽者的瀏覽。本文我們總結了五種SQL Server分頁儲存過程的方法,並對其效能進行了比較,接下來就讓我們來一起了解一下這一過程。 建立資料庫data_Test : create