许多应用程序都具有在同一时间从数据库表中的一个页面显示的数据网格。 许多人还让用户选择每页记录数,排序任何列,并导航来回结果。
什么是实现这个模式没有使整个表到客户端,然后筛选数据在客户端上一个好的算法。 你怎么只带要显示给用户的记录?
是否LINQ简化的解决方案?
许多应用程序都具有在同一时间从数据库表中的一个页面显示的数据网格。 许多人还让用户选择每页记录数,排序任何列,并导航来回结果。
什么是实现这个模式没有使整个表到客户端,然后筛选数据在客户端上一个好的算法。 你怎么只带要显示给用户的记录?
是否LINQ简化的解决方案?
在MS SQL Server 2005和以上, ROW_NUMBER()似乎工作:
T-SQL:分页与ROW_NUMBER()
DECLARE @PageNum AS INT;
DECLARE @PageSize AS INT;
SET @PageNum = 2;
SET @PageSize = 10;
WITH OrdersRN AS
(
SELECT ROW_NUMBER() OVER(ORDER BY OrderDate, OrderID) AS RowNum
,OrderID
,OrderDate
,CustomerID
,EmployeeID
FROM dbo.Orders
)
SELECT *
FROM OrdersRN
WHERE RowNum BETWEEN (@PageNum - 1) * @PageSize + 1
AND @PageNum * @PageSize
ORDER BY OrderDate
,OrderID;
我建议要么使用LINQ,或尝试复制它做什么。 我有一个应用程序,我使用LINQ采取和Skip方法来检索分页数据。 该代码看起来是这样的:
MyDataContext db = new MyDataContext();
var results = db.Products
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize);
运行SQL Server事件探查表明,LINQ是将这个查询到类似SQL:
SELECT [ProductId], [Name], [Cost], and so on...
FROM (
SELECT [ProductId], [Name], [Cost], [ROW_NUMBER]
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [Name]) AS [ROW_NUMBER],
[ProductId], [Name], [Cost]
FROM [Products]
)
WHERE [ROW_NUMBER] BETWEEN 10 AND 20
)
ORDER BY [ROW_NUMBER]
在纯英文:
1.您可以筛选行和使用ROW_NUMBER函数,你想要的顺序添加行号。
2.过滤器(1)到您的网页上只返回你想要的行号。
3.排序(2)行号,这是一样的,你想要的顺序(在这种情况下,名称)。
基本上有数据库(我假设你正在使用SQL Server)做分页的方式有两种:
其他人解释如何ROW_NUMBER() OVER()
排序函数可用来执行页面。 值得一提的是,SQL Server 2012的最后包括对SQL标准的支持OFFSET .. FETCH
子句:
SELECT first_name, last_name, score
FROM players
ORDER BY score DESC
OFFSET 40 ROWS FETCH NEXT 10 ROWS ONLY
如果您使用的SQL Server 2012和向后兼容性不是一个问题,你应该更喜欢这一条款,因为它会在角落里的情况更优化执行由SQL Server。
还有就是在SQL执行分页是完全不同的,速度更快,但鲜为人知的方式。 这通常被称为“求法”中的说明这里本博客文章 。
SELECT TOP 10 first_name, last_name, score
FROM players
WHERE (score < @previousScore)
OR (score = @previousScore AND player_id < @previousPlayerId)
ORDER BY score DESC, player_id DESC
该@previousScore
和@previousPlayerId
值与前一页的最后一条记录的相应值。 这使您可以获取“下一步”页面。 如果ORDER BY
方向是ASC
,只需使用>
代替。
通过上述方法,你不能直接跳到第4页,而不必首先取出先前的40条记录。 但往往,你不想跳那么远呢。 相反,你会得到一个可能能够在固定时间内取数据,这取决于你的索引速度更快的查询。 另外,你的页面保持“稳定”,不管底层数据的改变(例如,第1页上,当你第4页)。
这是当延迟加载更多的Web应用程序中的数据来实现分页,比如最好的办法。
请注意,在“求法”也被称为键集分页 。
LINQ:在.NET 3.5 lambda表达式和匿名类合并巨大简化了这样的事情。
查询数据库:
var customers = from c in db.customers
join p in db.purchases on c.CustomerID equals p.CustomerID
where p.purchases > 5
select c;
每页记录数:
customers = customers.Skip(pageNum * pageSize).Take(pageSize);
按任何列排序:
customers = customers.OrderBy(c => c.LastName);
正在从服务器只选定字段:
var customers = from c in db.customers
join p in db.purchases on c.CustomerID equals p.CustomerID
where p.purchases > 5
select new
{
CustomerID = c.CustomerID,
FirstName = c.FirstName,
LastName = c.LastName
};
这将创建在其中您可以访问它的属性静态类型匿名类:
var firstCustomer = customer.First();
int id = firstCustomer.CustomerID;
从查询的结果是延迟加载默认情况下,这样你就不会说话到数据库,直到你真正需要的数据。 LINQ在.NET还可以通过保持你所做的任何更改一个DataContext,只有更新您更改的字段极大地简化了更新。
Oracle解决方案:
select * from (
select a.*, rownum rnum from (
YOUR_QUERY_GOES_HERE -- including the order by
) a
where rownum <= MAX_ROW
) where rnum >= MIN_ROW
有我与MS SQL 2005中使用了几个解决方案。
其中之一是ROW_NUMBER()。 运行在第二查询数千超过1TB的数据 - - 不过,就个人而言,我不喜欢ROW_NUMBER(),因为它没有为大的结果(DB我工作的工作是非常大的,你知道 - 大社交网络现场)。
这里是我最喜欢的解决方案。
我会用那种T-SQL的伪代码。
让我们找到用的名字,姓氏,每一页都有10个记录整理用户的第2页。
@page = 2 -- input parameter
@size = 10 -- can be optional input parameter
if @page < 1 then begin
@page = 1 -- check page number
end
@start = (@page-1) * @size + 1 -- @page starts at record no @start
-- find the beginning of page @page
SELECT TOP (@start)
@forename = forename,
@surname = surname
@id = id
FROM
users
ORDER BY
forename,
surname,
id -- to keep correct order in case of have two John Smith.
-- select @size records starting from @start
SELECT TOP (@size)
id,
forename,
surname
FROM
users
WHERE
(forename = @forename and surname = @surname and id >= @id) -- the same name and surname, but bigger id
OR (forename = @forename and surname > @surname) -- the same name, but bigger surname, id doesn't matter
OR (forename > @forename) -- bigger forename, the rest doesn't matter
ORDER BY
forename,
surname,
id
事实上,LINQ已经跳过并采取可以组合选择哪些记录被获取的方法。
检查者淘汰。
对于DB: 分页在SQL Server 2005
有一个讨论关于这个这里
该技术从78ms 150,000线数据库中获取页面编号达到100000
采用优化的知识和SET ROWCOUNT,在请求被存储在一个起点,一个局部变量的页面的第一个雇员。 接下来,将rowcount设置的中请求@maximumRows的最大记录数。 这使得寻呼导致更有效的方式设置。 使用这种方法还利用预先存在的索引表上的,因为它直接进入基表,而不是在本地创建的表。
我怕我无法判断它是否比目前公认的答案更好。