in reply to Moving SQL from perl to Stored Procedures
For start 5, slice size 10, end 15: Select the results from 1..15 into @paging_buffer Assign a sort_idx to each row using an identity column Select the rows with a sort_idx > @slice_start
For start 5, slice size 10, end 15: Select the results from 1..15 into @paging_buffer Set the ROWCOUNT to @slice_start -1 Delete from @paging_bufferStrategy 1 outperforms strategy 2 by a fair amount, so I would recommend that one - thanks to Jenda for pointing out a flaw in my benchmarking.
An important note with strategy 2 is that if the start_slice = 1 you do not want to set the ROWCOUNT to 0 before deletion, as this will purge all the records from the buffer. This is bad.
An improvement over this design is to only store the keys required to uniquely identify the rows in the paging buffer, and then join the paging buffer back to the original tables. This reduces the amount of space used in the temp db.
If your query uses multiple tables then solution 2 will require join hints to force the join order, and to force a loop join. Hash/Merge joins will break the ordering of the result set, as will a different join order.
CREATE PROCEDURE [dbo].[paging_example] @slice_size int = 0, -- ROWCOUNT 0 will return all results @slice_start int = 1 AS declare @slice_end int set @slice_end = @slice_start + @slice_size - 1 -- Create a buffer for the records from 1..@slice_end declare @paging_buffer table( sort_id int not null identity(1,1) PRIMARY KEY, user_id int not null ); -- SELECT from 1 til the end of the slice into @paging_buffer SET ROWCOUNT @slice_end insert into @paging_buffer (user_id) SELECT user_id FROM Users ORDER BY lastname SET ROWCOUNT 0 select u.user_id, u.firstname, u.lastname from @paging_buffer buffer inner join Users u on u.user_id = buffer.user_id where buffer.sort_id >= @slice_start and buffer.sort_id <= @slice_end order by buffer.sort_id GO
CREATE PROCEDURE [dbo].[paging_example] @slice_size int = 0, -- ROWCOUNT 0 will return all results @slice_start int = 1 AS -- Create a buffer for the records from 1..@slice_end declare @paging_buffer table( user_id int ); declare @slice_end int set @slice_end = @slice_start + @slice_size - 1 -- SELECT from 1 til the end of the slice into @paging_buffer SET ROWCOUNT @slice_end insert into @paging_buffer SELECT user_id FROM Users ORDER BY lastname --This approach will delete the rows we don't need from the buffer -- If we're starting at #1 then we don't need to do anything special -- Delete will go in order, so if we delete up to the record before th +e start of the slice then only the desired records will remain DECLARE @discard_up_to int SET @discard_up_to = @slice_start - 1 SET ROWCOUNT @discard_up_to -- If the start_slice is 1, then setting the rowcount to 0 will result + in a complete delete - we don't want this -- But we also do not want to prevent if with an IF clause, because wh +en a stored procedure uses the 'IF' clause it will be recompiled befo +re each run. -- So instead we check "where @discard_up_to > 0" in the delete clause DELETE FROM @paging_buffer where @discard_up_to > 0 SET ROWCOUNT 0 select u.user_id, u.firstname, u.lastname from @paging_buffer buffer inner join Users u on u.user_id = buffer.user_id option (loop join, force order) GO
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: Moving SQL from perl to Stored Procedures - MSSQL tricks, dynamic paging
by dokkeldepper (Friar) on Sep 09, 2006 at 08:22 UTC | |
by Jenda (Abbot) on Sep 09, 2006 at 10:32 UTC | |
|
Re^2: Moving SQL from perl to Stored Procedures - MSSQL tricks, dynamic paging
by Jenda (Abbot) on Sep 09, 2006 at 10:46 UTC | |
by imp (Priest) on Sep 09, 2006 at 16:05 UTC |