Reputation: 3787
I use following query for paging in my application (MVC4, SQL Server):
string sql = "SELECT Id, Name, Date, allCount FROM (" +
"SELECT Id, Name, Date, COUNT(Id) OVER() as allCount, " +
"ROW_NUMBER() OVER (ORDER BY Date DESC, Id ) AS RowNum FROM Products) AS SOD " +
"WHERE SOD.RowNum BETWEEN ((@PageNumber-1)*@RowsPerPage)+1 AND @RowsPerPage*(@PageNumber) ORDER BY Date DESC";
This works for me, but I want to know is it a normal approach to count allCount many times? I am afraid that to count allCount many times, will affect the speed for bulk data. But, In view I need count of all products to make pagination. Is it normal code if not, how can I change it?
Upvotes: 0
Views: 179
Reputation: 15772
I would perhaps inline your Between operation parameters in your .net. You can control the calculation to run only once. I personally don't trust SQL server to decide what is "deterministic" since I have been bitten a few times. Also why do you need to return allcount in EVERY row. If you are using ADO.Net rather than an ORM, then you can control your SQL as you want.
Do
SELECT Count(*);
SELECT id,
name,
date
FROM (SELECT id,
name,
date,
Row_number()
OVER (
ORDER BY date DESC, id ) AS RowNum
FROM products) AS SOD
WHERE SOD.rownum BETWEEN @Start AND @End
ORDER BY date DESC
Although I suspect that you can just use a HAVING
clause instead of your inner query with WHERE
.
Upvotes: 1
Reputation: 10680
Even though it might seem from the resulting data, that the COUNT(Id)-operation is performed once for every record in the dataset, the count is in fact only performed once. The query optimizer knows that the expression COUNT(Id) OVER()
is independent of the current record, which allows it to only do the count once.
As such, I don't see anything wrong with your query, in terms of paging.
Upvotes: 1