I have an expensive query using the row_number over() functionality in SQL Server 2005. I return only a sub list of those records as the query is paginated. However, I wou
Over the years a pile of developer sweat has gone into efficiently paging result sets. Yet, there is no one answer--it depends on your use case. Part of the use case is getting your page efficiently, part is figuring out how many rows are in a complete result set. So sorry if i stray a little into paging, but the two are pretty tightly coupled in my mind.
There are a lot of strategies, most of which are bad if you have any sort of data volume & don't fit the use case. While this isn't a complete list, following are some of the options.....
Count(*)
WHERE/JOIN
criteria because running the WHERE/JOIN
twice is expensive.ROW_Number() OVER()
and COUNT(1) OVER(PARTITION By 1)
COUNT(*) OVER(PARTITION BY 1) as TotalRows
results in ~12,000 reads. Compare that to a simple SELECT COUNT(*) FROM Media
-- 12 reads. Wowzers. UPDATE -- the reads issue I mentioned is a bit of red-herring. It turns out, that with windowed functions the unit used to measure reads is kind of mixed. The net result is what appears to be massive numbers of reads. You can see more on the issue here : Why are logical reads for windowed aggregate functions so high?
Row_Number()
) the row count for 1 to N is (N + 1) - 1
. More explanation in the links. ROW_Number() OVER(Order by ID)
and ROW_Number() OVER(Order by ID DESC)
then sum the two numbers and subtract 1.Read my good man, read. Here are some articles that I've leaned on...
Hope that helps.
I do this by putting the whole resultset with the row_number into a temp table, then use the @@rowcount from that and use the query on that to return the page of data I need.
Check out the COUNT(*) aggregate when used with OVER(PARTITON BY..), like so:
SELECT
ROW_NUMBER() OVER(ORDER BY object_id, column_id) as RowNum
, COUNT(*) OVER(PARTITION BY 1) as TotalRows
, *
FROM master.sys.columns
This is IMHO the best way to do it without having to do two queries.
If count(*) is slow you really need to address that issue first by carefully examining your indexes and making sure your statistics are up to date.
In my experience, there is nothing better than doing two separate queries, one to get the data page, and one to get the total count. Using a temporary table in order to get total counts is a losing strategy as your number of rows increases. E.g., the cost of inserting 10,000,000 million rows into a temp table simply to count them is obviously going to be excessive.