Paging with 3 sub-queries with 1 connection vs 2 Queries with 2 connections

六月ゝ 毕业季﹏ 提交于 2019-12-13 07:22:54

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!