Paging in SQL Server

Published on March 2017 | Categories: Documents | Downloads: 47 | Comments: 0 | Views: 340
of 10
Download PDF   Embed   Report

Comments

Content

 

Introduction

Developers and database administrators have long debated methods for paging recordset results from Microsoft SQL Server, trying to balance ease of use with performance. The simplest methods were less efficient because they retrieved entire datasets from SQL Server before eliminating records which were not to be included, while the best-performing methods handled all paging on the server with more comple scripting. The !"#$%&M'(!)* !"#$%&M'(!)* function introduced in SQL Server + provides an efficient way to limit results relatively easily. easily. Paging Efficiency

n order to scale well, most applications only wor/ with a portion of the available data at a given time. #eb-based data maintenance applications are the most common eample of this, and several databindable 0S1.%(T classes )such as 2rid3iew and Datagrid* have built-in support for paging results. #hile it is possible to handle paging within the web page code, this may re4uire transferring all of the dataisfrom the database server to the weband server every ,time control updated. To improve performance efficiency efficiency, datathe which will not be used should be eliminated from processing as early as possible. Paging Methods

Many popular databases offer functions allowing you to limit which rows are returned for a given 4uery based upon their position within the record set. 5or eample, MySQL MySQL provides the LMT 4ualifier, which ta/es two parameters. The first LMT parameter specifies which )6ero-based* row number will be the first record returned, and the second parameter specifies the maimum number of records returned. The 4uery7 SELECT * FROM table LIMIT 20,13

...will return the +th through the 8+nd records -- assuming at least 88 records are available to return. f fewer than 88 records are available, the 4uery will return all records from record + on. f fewer than + records are available, none will be returned. SQL Server does not have this functionality functionality,, however the + release does have a number of other new tric/s. 5or instance, support for 9L! procedures means it is possible to use eisting paging methods to write 3'.%(T or 9: code that would eecute within the SQL Server environment. &nfortunately, 9L! procedures

 

are not as efficient as native Transact SQL. To ensure best performance, 4ueries should still be written in TSQL whenever practical. Using ROW_NUMBER()

TSQL in the + release includes the !"#$%&M'( !"#$%&M'(!)* !)* function, which adds an integer field to each record with the record;s ordinal result set number. Stated more simply, it adds the record;s position within the result set as an additional field so that the first record has a <, the second a +, etc. This may appear to be of little value, however by using nested 4ueries we can use this to our advantage. To demonstrate !"#$%&M'(!)* !"#$%&M'(!)* and to eplore how the paging solution wor/s, create a simple salary table and populate it with random data using the following commands7 CREATE TABLE [dbo].[Salarie]!   ["ero#] [#$ar%&ar]!'0( [#$ar%&ar]!'0 ( )OT )LL,   [i#%o+e] [+o#e] )OT )LL,  CO)STRAI)T -RIMAR E CLSTERE!   ["ero#][-/alarie] ASC (( O) [-RIMAR] O I)SERT I)SERT I)SERT I)SERT I)SERT I)SERT I)SERT I)SERT I)SERT I)SERT I)SERT I)SERT I)SERT I)SERT I)SERT I)SERT I)SERT

I)TO I)TO I)TO I)TO I)TO I)TO I)TO I)TO I)TO I)TO I)TO I)TO I)TO I)TO I)TO I)TO I)TO

Salarie Salarie Salarie Salarie Salarie Salarie Salarie Salarie Salarie Salarie Salarie Salarie Salarie Salarie Salarie Salarie Salarie

ALES ALES ALES ALES ALES ALES ALES ALES ALES ALES ALES ALES ALES ALES ALES ALES ALES

!45oe4, 4260004( !4S7e4, 4890004( !4Mi%&ael4, 4:'0004( !45o&#4, 49;0004( !4Ral"&4, 4160004( !4are#4, 4;30004( !4<aldo4, 4:;0004( !4E$a4, 4'10004( !4E+ero#4, 46:0004( !4Sta#le4, 4'80004( !45or=e4, 4:60004( !4Co#ta#%e4, 4'10004( !4A+elia4, 4390004( !4A##a4, 4:80004( !4a#ielle4, 4960004( !4Ste"&a#ie4, 4:;0004( !4Eli>abet&4, 4230004(

The !"#$%&M'(!)* !"#$%&M'(!)* function has no parameters - it simply adds the row number to each record in the result set. To ensure the numbering is consistent, however, SQL Server needs to /now how to sort the data. 'ecause of this, !"#$%&M'(!)* must immediately be followed by the "3(!)* function. "3(!)* has one re4uired parameter, which is an "!D(! '= clause. The basic synta for 4uerying the Salaries table is7

 

SELECT RO</)MBER!( OER!ORER B "ero#(, "ero#, i#%o+e FROM Salarie

This returns the following result7 (No (N o co colu lumn mn na name me)) pe perso rson n

in inco come me

1

Amelia

36000.00

2 3

Anna 49000.00 Constance 51000.00

4

Danielle

5

Elia!et" 23000.00

6

Emerson 84000.00

#

E$a

51000.00

8

%oe

28 28000.00

9

%o"n

6#000.00

10

%or&e

48000.00

11

'aren

#3000.00

12 13

ic"ael alp"

45000.00 18000.00

14

*tanle+

59000.00

15

*tep"anie 4#000.00

16

*ue

9 96 6000.00

1#

,al-o

4#000.00

68000.00

The Salaries data now appears sorted by person, and it has an etra column indicating each record;s position within the results. f for any reason you wanted the results to display in a different order than they were numbered in, you can include a different "!D(! '= clause as part of the normal S(L(9T synta7 SELECT RO</)MBER!( OER!ORER B "ero#(, "ero#, i#%o+e FROM Salarie ORER B i#%o+e

This returns the following result7 (No (N o co colu lumn mn na name me)) pe perso rson n

in inco come me

13

alp"

18000.00

5

Elia!et" 23000.00

8 1

%oe Amelia

28 28000.00 36000.00

 

12

ic"ael

45000.00

15

*tep"anie 4#000.00

1#

,al-o

4#000.00

10

%or&e

48000.00

2

Anna

49000.00

3

Constance 51000.00

#

E$a

51000.00

14

*tanle+

59000.00

9

%o"n

6#000.00

4

Danielle

68000.00

11

'aren

#3000.00

6

Emerson 84000.00

16

*ue

9 96 6000.00

f we want to limit the results displayed to a certain range, we need to nest this S(L(9T inside another one and provide a name for the !"#$%&M'(!)* column. To limit our results to records  through >, !"#$%&M'(!)* we can use the following 4uery7 SELECT * FROM !SELECT RO</)MBER!( OER!ORER B "ero#( AS ro?#7+, "ero#, i#%o+e FROM Salarie( AS Salarie1 <@ERE ro?#7+  ' A) ro?#7+  8

This returns the following result7 ron ronum um pe perso rson n

in inco come me

5

Elia!et" 23000.00

6

Emerson 84000.00

#

E$a

51000.00

8

%oe

28000.00

9

%o"n

6#000.00

 0gain, we can change the sort order by adding an "!D(! "!D(! '= clause. This is most easily accomplished by using the outer S(L(9T statement7 SELECT * FROM !SELECT RO</)MBER!( OER!ORER B "ero#( AS   ro?#7+, "ero#, i#%o+e FROM Salarie( AS Salarie1 <@ERE ro?#7+  ' A) ro?#7+  8 ORER B i#%o+e

 

This returns the following result7 ron ronum um pe perso rson n

in inco come me

5

Elia!et" 23000.00

8

%oe

28000.00

#

E$a

51000.00

9 6

%o"n 6#000.00 Emerson 84000.00

f we want to support the same type of arguments that MySQL;s LMT)* supports, we can create a stored procedure that accepts a beginning point and a maimum number of records to return. !"#$%&M'(! !"#$%&M '(! re4uires that the data be sorted, so we will also have a re4uired parameter for the "!D(! '= clause. (ecute the following statement to create a new stored procedure7 CREATE -ROCERE [dbo].["a=eSalarie]   Dtart i#t  1  ,D+a%t i#t  '  ,Dort #$ar%&ar!200 #$ar%&ar!200( ( AS   SET )OCO)T O)   ECLARE   DSTMT #$ar%&ar!+a(, #$ar%&ar!+a(,  SGL tate+e#t to ee%7te   D7bo7#d i#t   IF Dtart Dtart    IF D+a%t D+a%t    SET D7bo7#d   SET DSTMT      4( AS ro?, *         EEC !DSTMT(

1 1  4

SET Dtart  1 SET D+a%t  1 Dtart H D+a%t SELECT "ero#, i#%o+e FROM ! SELECT RO</)MBER!( OER!ORER B 4 H Dort H FROM Salarie ( AS tbl <@ERE

ro?  4 H CO)ERT!$ar%&ar!8(, CO)ERT!$ar%&ar!8(, Dtart( H 4 A) ro?  4 H CO)ERT!$ar%&ar!8(, CO)ERT!$ar%&ar!8(, D7bo7#d(  ret7r# reJ7eted re%ord

The pageSalaries procedure begins with S(T %"9"&%T "% to disable the record count message )a common step for optimi6ing 4uery performance*. #e then declare two necessary variables, ?STMT and ?ubound. 'ecause we want to be able to change what "!D(! '= argument is used, we need to dynamically generate our 4uery statement by storing it in ?STMT. The net lines ensure that only positive numbers are used for the starting position and maimum si6e, then calculate the range of !"#$%&M !"#$%&M'(!)* '(!)* values being re4uested. )f we wanted to be 6ero-based li/e MySQL;s LMT, we could do so with a few minor twea/s.* "nce the dynamic SQL

 

command has been strung together, it is eecuted so that the results are returned. (ecute the following statement to test the stored procedure7 "a=eSalarie :, ;, 4i#%o+e4

This returns the following result7  person

income

Amel Am elia ia

3600 36000. 0.00 00

ic" i c"ae aell

45 4500 000. 0.00 00

*tep"anie 4#000.00 ,al,a l-o o

4#0 #000 00.0 .00 0

%or&e

48000.00

Anna

49000.00

Constance 51000.00

f we eecute7 "a=eSalarie 13, ;, 4i#%o+e4

we receive bac/7  person

income

%o %o" "n

6#000.00

Danielle 68000.00 'are 'a ren n

#300 #3000. 0.00 00

Emerson 84000.00 *ue

96000.00

... because the 4uery goes beyond the number of records available. Ta/ing this one step further, we can ma/e a stored procedure that does a more general form of paging. n fact, it can be generali6ed to the point that it can be used to return any collection of fields, in any order, with any filtering clause. To create this wunder/ind marvel, eecute the following command7 CREATE -ROCERE [dbo].[7til-AE]   Ddatar% #$ar%&ar!200(  ,DorderB #$ar%&ar!200(  ,DKieldlit #$ar%&ar!200(  4*4  ,DKilter #$ar%&ar!200(  44  ,D"a=e)7+ i#t  1

 

 ,D"a=eSi>e i#t  )LL AS   SET )OCO)T O)   ECLARE   DSTMT #$ar%&ar!+a(   ,Dre%%t i#t "a=i#= i#terKa%e(

 SGL to ee%7te  total  oK re%ord !Kor ridie?

  IF LTRIM!RTRIM!DKilter((  44 SET DKilter  41  14   IFSET D"a=eSi>e )LL BEI)   DSTMT IS4SELECT 4 H DKieldlit H 4FROM 4 H Ddatar% H   4<@ERE 4 H DKilter H 4ORER B 4 H DorderB   EEC !DSTMT(  ret7r# reJ7eted re%ord E) ELSE BEI)   SET DSTMT  4SELECT Dre%%t  CO)T!*(   FROM 4 H Ddatar% H 4   <@ERE 4 H DKilter   EEC "/ee%7teSGL "/ee%7teSG L DSTMT, D"ara+  )4Dre%%t I)T OT-T4, Dre%%t  Dre%%t OT-T   SELECT Dre%%t AS re%%t  ret7r# t&e total  oK re%ord      

ECLARE Dlbo7#d i#t, D7bo7#d i#t

  SET D"a=e)7+  ABS!D"a=e)7+(   SET D"a=eSi>e  ABS!D"a=eSi>e( ABS!D"a=eSi>e(   IF D"a=e)7+  1 SET D"a=e)7+  1   IF D"a=eSi>e  1 SET D"a=eSi>e  1   SET Dlbo7#d  !!D"a=e)7+  1( * D"a=eSi>e(   SET D7bo7#d  Dlbo7#d H D"a=eSi>e H 1   IF Dlbo7#d  Dre%%t BEI)   SET D7bo7#d  Dre%%t H 1   SET Dlbo7#d  D7bo7#d  !D"a=eSi>e H 1(  ret7r# t&e lat "a=e oK re%ord iK  #o re%ord ?o7ld be o# t&e    "e%iKied "a=e   E)   SET DSTMT  4SELECT 4 H DKieldlit H 4   FROM !   DorderB H 4( AS ro?, *         <@ERE   A)     EEC !DSTMT( E)

SELECT FROM <@ERE ( AS tbl

RO</)MBER!( OER!ORER B 4 H 4 H Ddatar% H 4 4 H DKilter H 4

ro?  4 H CO)ERT!$ar%&ar!8(, CO)ERT!$ar%& ar!8(, Dlbo7#d( H 4 ro?  4 H CO)ERT!$ar%&ar!8(, CO)ERT!$ar%& ar!8(, D7bo7#d(  ret7r# reJ7eted re%ord

=ou may receive the following error message from SQL Server, which you can confidently ignore7 Ca##ot add ro? to .Jl/de"e#de#%ie Kor t&e tored "ro%ed7re be%a7e it de"e#d o# t&e +ii#= table 4"/ee%7teSGL4. T&e tored

 

"ro%ed7re ?ill till be %reated &o?e$er, it %a##ot be 7%%eK7ll ee%7ted 7#til t&e table eit.

The util1age procedure accepts @ parameters7 /-atasrc /or-er /or -er+ + /iel-l /ie l-lis is /il ilter   /pa&eNum /pa&eN um /pa&e*ie /pa&e* ie

 t"e ta!le (or store- proce-ure etc.) name  t"e DE DE  clause clause  t"e iel-s iel-s to return return (inclu (inclu-in -in& & calcul calculateate- epress epression ions) s)  t"e ,7EE clau ause se  t"e pa&e pa&e to return return (must (must !e !e &reater &reater t"an or or eual to one) one)  t"e num!er num!er o recor-s recor-s per pa&e

The stored procedure needs the name of a data source to 4uery against )such as a table* and one or more fields to sort by )since "3(!)* re4uires an "!D(! '= clause*. f ?filter is blan/ )the default*, it will be set to A< B <A as a simple way to select all records. f ?pageSi6e is not supplied, the 4uery will run without paging and will not return a record count. f, however, ?pageSi6e is supplied, a version of the 4uery is eecuted to get the total number of records.and n order have this record count available within the procedure as a to returned value, we use sp$eecuteSQL to support eecuting the statement while returning an output parameter. The record count is used to prevent returning empty results when possible, and to support paging interfaces that calculate the number of pages available )such as 2rid3iew*. f we were calling this stored procedure to populate a 2rid3iew, we would return ?recct as a !eturn3alue parameter instead of using a result set, but we will use a result set for demonstration purposes. The procedure calculates what the actual record positions will be for the re4uested page. !ather than allow the 4uery to fail, there are safety chec/s ensuring that ?pageSi6e and ?page%um are greater than 6ero, and that the result set will not be empty. f the specified page is out of range, this procedure will return the last possible page of records. This is helpful if a user changes more than one setting before refreshing their data, or if a significant amount of data is deleted between re4uests. The remainder of the procedure is virtually identical to the pageSalaries procedure. To test the util102( stored procedure, eecute the following statement7 7til-AE 4Salarie4, 4"ero#4, 4*4, 4i#%o+e  10004, 2, :

This returns the following two result sets7

 

recct 1# ro ro pe perso rson n

inco income me

5

Eli Elia! a!et" et" 23 2300 000 0

6

Emerso erson n 84 8400 000 0

#

E$a E$

51000

8

%oe %o

28000

f we eecute7 7til-AE 4Salarie4, 4"ero#4, 4"ero#, i#%o+e4, 44, 13, 3

...we receive bac/7 recct 1#  person

income

*tep"anie 4#000 *ue

96000

,al-o

4#000

(ven though the re4uest should be for records 8@ through 8C - far outside of what is available - the procedure returns the last available page of records. n contrast, re4uesting the third page with seven records per page using7 7til-AE 4Salarie4, 4"ero#4, 4"ero#, i#%o+e4, 44, 3, ;

...returns the last three records, as the page is not completely out of bounds7  person

income

*tep"anie 4#000 *ue

96000

,al-o

4#000

 0ll of these eamples eamples are based on simple single-t single-table able 4ueries, which may not reflect what you need in the real world. #hile the util102( procedure does not support ad-hoc "%s, it does wor/ with SQL 3iews. f you want paging support for multi-table 4ueries,

 

you should create a 3iew )with all of the necessary "%s* to use as the data source. &sing a 3iew follows good design practices as it ensures that your oins are performed consistently, consistently, allows easier adhoc 4uerying from the command line, and is much easier to troubleshoot than a stored procedure;s dynamic S(L(9T statement logic. Conclusion

#hile SQL Server does not have as simple a method for paging results as some other databases, features introduced in the + release have made it possible to page results efficiently more easily than ever before. n the net article in this series, we will go a step further and integrate this paging logic with a 2rid3iew through a Data  0ccess Layer. Layer.

Sponsor Documents

Or use your account on DocShare.tips

Hide

Forgot your password?

Or register your new account on DocShare.tips

Hide

Lost your password? Please enter your email address. You will receive a link to create a new password.

Back to log-in

Close