应该很多人也遇到过这个问题,大概在2年前我也遇到过标题中的问题,当时研究了几天很是纠结没能彻底解决问题,后来也找了很多方法没能解决问题。最近又遇到这个问题,实在是不解决也不行了,冷静的想了想,完善了一下分页查询的方法,现在把代码贴上,给大家参考,若有什么漏洞,请及时联系吉日嘎拉,有错我会积极修正。希望不要重复浪费生命,直接拿过去用就可以了,在通用权限管理系统组件里也用了这个方法在进行分页。
最近维护一个每天有10万多IP访问的网站,也是用了这个分页存储过程,分页效率还可以,最后一页没在出现卡死状态,若有问题及时联系作者QQ:252056973,欢迎大家交流分享。当系统有少数几个用户实用时问题也不严重,但是系统每时每刻都有很多人访问时那就闹心了,很容易产生网站效率极低的,访问量严重下降的趋势。
最后一页分页一卡死,整个网站的性能都会非常明显的下降,不知道为啥,微软有这个BUG一直没处理好。希望SQL2012里不要有这个问题就好了。
参考代码如下:
-- Author: 吉日嘎拉
-- Create date: 2012年02月23日
-- Description: 2012年02月23日编码规范化
-- =============================================
ALTER PROCEDURE [dbo].[GetRecordByPage]
@TableName VARCHAR( 4000), -- 表名
@SelectField VARCHAR( 4000), -- 要显示的字段名(不要加select)
@WhereConditional VARCHAR( 4000), -- 查询条件(注意: 不要加 where)
@SortExpression VARCHAR( 255), -- 排序索引字段名
@PageSize INT = 20, -- 页大小
@PageIndex INT = 1, -- 页码
@RecordCount INT OUTPUT, -- 返回记录总数
@SortDire VARCHAR( 5) = ' DESC ' -- 设置排序类型, 非 0 值则降序
AS
BEGIN
DECLARE @commandText VARCHAR( 8000) -- 主语句
DECLARE @TopN INT -- 获取前几条记录
DECLARE @PageCount INT -- 总共会是几页
DECLARE @TopLimit INT -- 获取多少条记录
DECLARE @SQLRowCount NVARCHAR( 4000) -- 用于查询记录总数的语句
DECLARE @SQLOrder VARCHAR( 400) -- 排序类型
DECLARE @SQLTemp VARCHAR( 4000) -- 临时变量
SET @SortExpression = LTRIM(RTRIM(@SortExpression))
SET @SortDire = UPPER(LTRIM(RTRIM(@SortDire)))
-- 这里是计算整体记录行数
IF @RecordCount IS NULL
BEGIN
IF @WhereConditional != ''
BEGIN
SET @SQLRowCount = ' SELECT @RecordCount=COUNT(1) FROM ' + @TableName + ' WHERE ' + @WhereConditional
END
ELSE
BEGIN
SET @SQLRowCount = ' SELECT @RecordCount=COUNT(1) FROM ' + @TableName
END
END
-- SELECT @RecordCount=@@ROWCOUNT
EXEC sp_executesql @SQLRowCount, N ' @RecordCount INT OUT ', @RecordCount out
IF @RecordCount IS NULL
BEGIN
SET @RecordCount = 0
END
-- 这里是控制页数最多少
SET @PageCount = @RecordCount / @PageSize + 1
-- 这里检查当前页的有效性
IF (@PageIndex < 1)
BEGIN
SET @PageIndex = 1
END
-- 这里限制最后一页的有效性
IF (@PageIndex > @PageCount)
BEGIN
SET @PageIndex = @PageCount
END
IF @SortDire != ' ASC '
BEGIN
SET @SQLTemp = ' <(SELECT MIN '
SET @SQLOrder = ' ORDER BY ' + @SortExpression + ' DESC '
END
ELSE
BEGIN
set @SQLTemp = ' >(SELECT MAX '
set @SQLOrder = ' ORDER BY ' + @SortExpression + ' ASC '
END
-- 这里是调试信息
-- SELECT @SQLOrder
-- 获取几条数据? 吉日嘎拉 2010- 11- 02 更新
SET @TopN = @RecordCount - @PageSize * (@PageIndex - 1)
IF @TopN > @PageSize
BEGIN
SET @TopN = @PageSize
END
SET @TopLimit = @PageSize * (@PageIndex - 1)
IF @TopLimit > @RecordCount
BEGIN
SET @TopLimit = @RecordCount
END
SET @commandText = ' SELECT TOP ' + STR(@TopN) + ' ' + @SelectField + ' FROM '
+ @TableName + ' WHERE ' + @SortExpression + @SQLTemp + ' ( '
+ RIGHT(@SortExpression, LEN(@SortExpression) - CHARINDEX( ' . ', @SortExpression)) + ' ) FROM (SELECT TOP ' + STR(@TopLimit)
+ ' ' + @SortExpression + ' FROM ' + @TableName + @SQLOrder + ' ) AS TableTemp) '
+ @SQLOrder
IF @WhereConditional != ''
SET @commandText = ' SELECT TOP ' + STR(@TopN) + ' ' + @SelectField + ' FROM '
+ @TableName + ' WHERE ' + @SortExpression + @SQLTemp + ' ( '
+ RIGHT(@SortExpression, LEN(@SortExpression) - CHARINDEX( ' . ',@SortExpression)) + ' ) FROM (SELECT TOP ' + STR(@TopLimit)
+ ' ' + @SortExpression + ' FROM ' + @TableName + ' WHERE ' + @WhereConditional + ' '
+ @SQLOrder + ' ) AS TableTemp) AND ' + @WhereConditional + ' ' + @SQLOrder
IF @PageIndex = 1
BEGIN
-- 第一页的显示效率提高
SET @SQLTemp = ''
IF @WhereConditional != ''
SET @SQLTemp = ' WHERE ' + @WhereConditional
SET @commandText = ' SELECT TOP ' + STR(@TopN) + ' ' + @SelectField
+ ' FROM ' + @TableName + @SQLTemp + ' ' + @SQLOrder
END
ELSE
BEGIN
-- 解决大数据最有一页卡死的问题
IF @PageIndex = @PageCount
BEGIN
IF @SortDire = ' ASC '
BEGIN
SET @SQLOrder = ' ORDER BY ' + @SortExpression + ' DESC '
END
ELSE
BEGIN
SET @SQLOrder = ' ORDER BY ' + @SortExpression + ' ASC '
END
SET @SQLTemp = ''
IF @WhereConditional != ''
SET @SQLTemp = ' WHERE ' + @WhereConditional
SET @commandText = ' SELECT TOP ' + STR(@TopN) + ' ' + @SelectField
+ ' FROM ' + @TableName + @SQLTemp + ' ' + @SQLOrder
SET @commandText = ' SELECT ' + @SelectField
+ ' FROM ( ' + @commandText + ' ) AS TableTemp ORDER BY ' + @SortExpression + ' ' + @SortDire
END
END
EXEC (@commandText)
-- 这个是调试程序用的
-- SELECT @commandText
END
吉日嘎拉(蒙古语为吉祥如意),2000年毕业于黑龙江大学计算机系软件专业,目前定居杭州,典型的IT软件土鳖一个,外号“软件包工头”。
通用权限管理系统组件(GPM - General Permissions Manager)自2003年开始发布,目前是国内注册用户和免费盗版用户最多的权限管理系统,是各种信息管理系统开发中彻底的权限解决方案。本组件支持多种主流数据库(Oracle、sqlsever、db2、mysql),功能强大,使用方便,代码简洁,思路严谨,被广大支持者称为权限管理系统中的“走火入魔级权限管理系统”。
精心维护通用权限管理系统组件(GPM - General Permissions Manager)有8年多,3年的不断推广,20万行经典的业务逻辑积累,经过上万次的调试修正,经历了四百个付费客户,上百软件公司的实战开发。
11年以上开发经验,外企工作5年,上市公司3年,独立经营软件公司2年,主持研发部门管理工作4年以上。
将权限管理、工作流做到我能力的极致,一个人只能做好那么很少的几件事情。
QQ:252056973,Mail:jirigala_bao@hotmail.com
通用权限管理模块的严谨设计定位、精心编码实现、不断维护推广、持续优化改进,主要是为了实现一个可以高度重复利用劳动成果的工具软件并有偿提供给所需的人们,另想成为国人值得骄傲的知名软件功能模块。
可供国内管理类开发人员在日常工作中进行灵活二次开发利用的模块,开发管理类软件的必备工具之一,我们的目标就是让程序员早点儿回家休息。