问题
I have been doing a lot of research on Paging and I am stuck between two methods. With both approaches I will be using PagedList.MVC to display my pages, however the problem lies in how do I pass the data to the PagedList and which of my two methods is more efficient.
The best example I have found out there is as follows:
public static PagedList<Customer> GetPagedCustomers(int skip, int take)
{
using (var context = new AdventureWorksLTEntities())
{
var query = context.Customers.Include("SalesOrderHeaders")
.Where(c => c.SalesOrderHeaders.Any())
.OrderBy(c => c.CompanyName + c.LastName + c.FirstName);
var customerCount = query.Count();
var customers = query.Skip(skip).Take(take).ToList();
return new PagedList<Customer>
{
Entities = customers,
HasNext = (skip + 10 < customerCount),
HasPrevious = (skip > 0)
};
}
}
Reference to original article
If you look carefully in that code, there are actually 2 queries happening, one after the other. The first one is var customerCount = query.Count();
and the second one is var customers = query.Skip(skip).Take(take).ToList();
While I love the approach above of the query being very light weight and only retrieving 10 records at a time, I do not like that it hits the database twice.
My second approach is more custom and involves running the query directly on the server along with pagination. Now this query is being run with Dapper currently, but I'll work my way to EF6 if the responses here agree with me.
SELECT *
FROM (
SELECT
*,1 as SplitOn,
(ROW_NUMBER() OVER(ORDER BY @SortColumn )) AS RowNum, COUNT(*) over() as TotalRows
FROM (
@CustomQuery
) AS FirstQuery
) AS TEMP
WHERE RowNum BETWEEN 1 + ((@Page - 1) * @PageSize) AND @Page * @PageSize
To parse that with dapper, the code looks something like this
var simpleQuery = "Select * FROM Customers";
var finalQuery = string.Format(pageQuery, simpleQuery)
var obj = myWrapper();
using (var oConn = CreateConnection(ConnectionString))
{
TotalPages totalRows = null;
var list = oConn.Query<T, TotalPages, T>(finalQuery, (e, t) =>
{
totalRows = t;
if (mapAction != null) mapAction(e);
return e;
}, param, splitOn: "SplitOn");
}
obj.RowsFound = (IEnumerable<dynamic>)list;
obj.TotalRows = totalRows == null ? 0 : totalRows.TotalRows;
Few things in the above are being passed in such as the type <T>
, object param
, Action<T> mapAction
and those things are not important for my question, as the question is this:
In the first example I am querying twice. In the second example I am querying once, but I am doing essentially 1 query and 2 sub queries within. Which is more efficient against a table that has server million records and is being hit quite often as it has a lot of traffic. My goal is to understand is it better to query essentially 3 times on the server within one connection. or to do 2 queries with 2 separate connections to the database.
EDIT:
I gave this a bit more thought, and the first example is actually 2 subqueries as well. Due to nature of query not executing until you call ToList() method, it will only append the query and build it up.
So honestly, I really believe the second method to be better, but I was hoping to get some assurances.
来源:https://stackoverflow.com/questions/40893646/paging-with-3-sub-queries-with-1-connection-vs-2-queries-with-2-connections