Fab*_*bio 26 sql-server pagination common-table-expression
我想用分页进行数据库查询.所以,我使用了一个通用表表达式和一个排名函数来实现这一点.看下面的例子.
declare @table table (name varchar(30));
insert into @table values ('Jeanna Hackman');
insert into @table values ('Han Fackler');
insert into @table values ('Tiera Wetherbee');
insert into @table values ('Hilario Mccray');
insert into @table values ('Mariela Edinger');
insert into @table values ('Darla Tremble');
insert into @table values ('Mammie Cicero');
insert into @table values ('Raisa Harbour');
insert into @table values ('Nicholas Blass');
insert into @table values ('Heather Hayashi');
declare @pagenumber int = 2;
declare @pagesize int = 3;
declare @total int;
with query as
(
select name, ROW_NUMBER() OVER(ORDER BY name ASC) as line from @table
)
select top (@pagesize) name from query
where line > (@pagenumber - 1) * @pagesize
Run Code Online (Sandbox Code Playgroud)
在这里,我可以指定@pagesize和@pagenumber变量来为我提供我想要的记录.但是,此示例(来自存储过程)用于在Web应用程序中进行网格分页.此Web应用程序需要显示页码.例如,如果数据库中有12条记录且页面大小为3,那么我将必须显示4个链接,每个链接代表一个页面.
但是,如果不知道有多少记录,我不能这样做,这个例子只给了我记录的子集.
然后我更改了存储过程以返回计数(*).
declare @pagenumber int = 2;
declare @pagesize int = 3;
declare @total int;
with query as
(
select name, ROW_NUMBER() OVER(ORDER BY name ASC) as line, total = count(*) over()from @table
)
select top (@pagesize) name, total from query
where line > (@pagenumber - 1) * @pagesize
Run Code Online (Sandbox Code Playgroud)
因此,与每一行一起,它将显示记录的总数.但我不喜欢它.
我的问题是,如果有更好的方法(性能),可以设置@total变量而不在SELECT中返回此信息.或者这个总列是否会对性能造成太大影响?
谢谢
Bla*_*ack 49
假设您正在使用MSSQL 2012,您可以使用Offset and Fetch
它来大大清理服务器端分页.我们发现性能很好,而且在大多数情况下更好.获取总列数,只需使用内联下面的窗口函数...它不包括'offset'和'fetch'施加的限制.
对于Row_Number,你可以按照你的方式使用窗口函数,但我建议你将客户端计算为(pagenumber*pagesize + resultsetRowNumber),所以如果你在10个结果的第5页和第3行你将输出第53行.
当应用于订单表约200万个订单时,我发现以下内容:
快速版本
这发生在一秒钟之内.关于它的好处是你可以在公共表表达式中进行一次过滤,它既适用于分页过程又适用于计数.当where子句中有许多谓词时,这会使事情变得简单.
declare @skipRows int = 25,
@takeRows int = 100,
@count int = 0
;WITH Orders_cte AS (
SELECT OrderID
FROM dbo.Orders
)
SELECT
OrderID,
tCountOrders.CountOrders AS TotalRows
FROM Orders_cte
CROSS JOIN (SELECT Count(*) AS CountOrders FROM Orders_cte) AS tCountOrders
ORDER BY OrderID
OFFSET @skipRows ROWS
FETCH NEXT @takeRows ROWS ONLY;
Run Code Online (Sandbox Code Playgroud)
慢速版
这花费了大约10秒,而计数(*)导致了缓慢.我很惊讶这是如此之慢,但我怀疑它只是计算每一行的总数.虽然这很干净.
declare @skipRows int = 25,
@takeRows int = 100,
@count int = 0
SELECT
OrderID,
Count(*) Over() AS TotalRows
FROM Location.Orders
ORDER BY OrderID
OFFSET @skipRows ROWS
FETCH NEXT @takeRows ROWS ONLY;
Run Code Online (Sandbox Code Playgroud)
结论
我们之前已经完成了这个性能调优过程,并且实际上发现它依赖于查询,使用的谓词和涉及的索引.例如,第二个我们引入了一个视图,因此我们实际查询基表,然后连接视图(包括基表),它实际上表现非常好.
我建议有几个直接的策略,并将它们应用于高价值的查询.
归档时间: |
|
查看次数: |
70878 次 |
最近记录: |