公用ms sql 分页存储过程

王朝互联网·作者佚名  2012-04-19
窄屏简体版  字體: 小  |  中  |  大  |  超大  

在编写分页存储过程前我们先为数据库创建一个测试表,这个测试表明叫做order,当中有3个字段,分别是or_id,orName,dateSta;下面创建表脚本:

CREATE TABLE [dbo].[Orders](

[or_id] [int] IDENTITY(1,1) NOT NULL,

[orName] [nvarchar](50) NOT NULL,

[dateSta] [datetime] NOT NULL,

CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED

(

[or_id] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

) ON [PRIMARY]

GO

EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'写入时间' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Orders', @level2type=N'COLUMN',@level2name=N'dateSta'

GO

SET IDENTITY_INSERT [dbo].[Orders] ON

INSERT [dbo].[Orders] ([or_id], [orName], [dateSta]) VALUES (1, N'naoqiu.com', CAST(0x0000A03700FEF029 AS DateTime))

INSERT [dbo].[Orders] ([or_id], [orName], [dateSta]) VALUES (2, N'naoqiu.com', CAST(0x0000A03700FF5BE8 AS DateTime))

INSERT [dbo].[Orders] ([or_id], [orName], [dateSta]) VALUES (3, N'押金', CAST(0x0000A03700FF5BF6 AS DateTime))

INSERT [dbo].[Orders] ([or_id], [orName], [dateSta]) VALUES (4, N'费用', CAST(0x0000A03700FF5BF6 AS DateTime))

INSERT [dbo].[Orders] ([or_id], [orName], [dateSta]) VALUES (5, N'http://naoqiu.com', CAST(0x0000A03700FF5BF6 AS DateTime))

SET IDENTITY_INSERT [dbo].[Orders] OFF

/****** Object: Default [DF_Orders_dateSta] script Date: 04/18/2012 15:31:11 ******/

ALTER TABLE [dbo].[Orders] ADD CONSTRAINT [DF_Orders_dateSta] DEFAULT (getdate()) FOR [dateSta]

GO

现在我们先看在sql 2005上传统的分页存储过程:

Create Procedure [dbo].[prPageList]

(

@PageSize int=20,/*每页行数*/

@PageIndex int=1,/*传进页数*/

@Field nvarchar(2000),/*查询字段*/

@QueryString nvarchar(3000),/*查询语句*/

@Orderby nvarchar(1000)/*排序字段*/

)

AS

Set NoCount ON

Declare @list_id1 int,@list_id2 int

DECLARE @SqlQuery nvarchar(4000)

Set @list_id2=(@PageSize*@PageIndex)--当前页记录结束

Set @list_id1=(@list_id2-@PageSize)--当前页记录开始

Set @SqlQuery=N'Select * From (Select ROW_NUMBER() Over(order by '

+@Orderby

+N')AS list_id,'

+@Field

+' '

+@QueryString

+N')AS A Where A.list_id>'

+Cast(@list_id1 AS Nvarchar)

+N' and A.list_id<='

+Cast(@list_id2 AS Nvarchar)

print @SqlQuery

Execute sp_executesql @SqlQuery

Set @SqlQuery='Select count(*) '+@QueryString

Execute sp_executesql @SqlQuery

RETURN

调用示例:exec prPageList 10,100,'orderID','from orders','dateSta desc'

这种的编写有以下优点:

公用分页存储过程代码精简,易理解

调用比较简单,参数少。

缺点:字符串超过4000该存储过程执行会发生异常;需要执行两次检索表,花费资源大;当选择第二页,还需要执行两次,一次是列表,一次是统计总数。

现在在同等情况下为了提高性能,提高语句执行效率。需要对以上的分页存储过程的逻辑思路进行个调整:

在未统计分页总数情况统计分页总数,当已经统计过分页总数,可不需要再次统计分页总数。

在我们第一位统计分页总数时,我们需要统计分页总数,现在我们使用临时表将符合条件的记录id插入到临时表,以方便检索以及统计。 这样我们就避免来两次扫描全表。

在多表关联筛选数据情况下,我们筛选的条件可能就只在某几张表,而显示结果可能需要关联更多的表情况下,那我们可以将筛选插入临时表的关联条件与显示列表关联条件作成不一样。以准证兼容更强。

在我们执行分页过程中,可能会产生中间临时表去管理其他的表。

以及完成之后我们可以直接使用到的临时表删除释放资源,而不是等待sql帮我做垃圾回收处理。

更具以上的思路,现在我直接把代码贴出来:

--综合公用分页存储过程

Create procedure [dbo].[Test_Common_PageList_TemTableByRelation]

@pageIndex int,--当前页索引,第一页为:1

@pageSize int,--每页显示条数

@count int,--总数第一次传0

@id varchar(40),--主键id或关联字段

@sortparam varchar(50),--排序

@selectParam nvarchar(2000),--查询字段

@condition nvarchar(2000),--查询条件

@temTable nvarchar(3000),--临时表字符串

@dropTable varchar(300),--删除临时表字符串

@relation varchar(2000),--关联表

@insrtParam varchar(100),--插入到统计总量临时表的字段

@param varchar(100)--插入到页显示的临时表字段

as

declare @sql nvarchar(4000),@min int,@max int,@date varchar(15),@tem1 varchar(20),@tem2 varchar(20),@part2 nvarchar(4000)

set @date=replace(CONVERT(varchar,getdate(),114),':','')

set @tem1='#page1'+@date

set @tem2='#page2'+@date

set @min=(@pageIndex-1)*@pageSize+1

set @max=@pageIndex*@pageSize

set @sql='

select '+@id+' as spkid'+@insrtParam+',ROW_NUMBER() OVER (ORDER BY '+@sortparam+') AS RowNumber into '+@tem1+' from '+@condition+'

select spkid,RowNumber'+@param+' into '+@tem2+' from '+@tem1+' where RowNumber between '+CAST(@min as varchar(11))+' and '+

CAST(@max as varchar(11))

if @count=0 begin

set @part2='declare @count int

set @count=(select max(RowNumber) from '+@tem1+')

if @count is null set @count=0

select '+@selectParam+',@count as num'

end else begin

set @part2='select '+@selectParam+','+CAST(@count as varchar(11))+' as num'

end

set @part2=@part2+',RowNumber from '+@tem2+' as pt join '+@relation+' order by pt.RowNumber

truncate table '+@tem1+'

truncate table '+@tem2+'

drop table '+@tem1+'

drop table '+@tem2+'

'+@dropTable

--关闭影响行数

exec('set nocount on

'+@temTable+@sql+@part2+'

set nocount off')

--打开影响行数

GO

调用方法示例:

SET STATISTICS IO on -- 查看磁盘IO

set statistics time on -- 查看sql语句分析编译和执行时间

declare @count int

set @count=0

exec [dbo].[Erp_Common_PageList_TemTableByRelation] 1,50,@count,'or_id','dateSta desc',

' * ','orders','','','orders on spkid=or_id','',''

总结:在读取数据过程中尽可能的减少表逻辑读取次数,以及扫描次数,减少io输出是提高性能的保证。

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航