一个通用的分页存储过程实现-SqlServer(附上sql源码,一键执行即刻搭建运行环境)

使用前提

  查询表必须有ID字段,且该字段不能重复,建议为自增主键

背景

  如果使用ADO.NET进行开发,在查询分页数据的时候一般都是使用分页存储过程来实现的,本文提供一种通用的分页存储过程,只需要传入:

  1. 表名(以DBName.dbo.TableName)的形式
  2. Where条件(ID > 0 AND ID < 100)
  3. Select字段(ID,NAME,CreateDate)
  4. Order字段(NAME ASC,CreateDate DESC)
  5. PageSize (15)
  6. PageIndex(2)
  7. TotalCount,此为output参数

  这7个参数,存储过程就能够返回指定条件下的分页数据,和数据总数。

sql源码&测试环境搭建

--创建Util库
CREATE DATABASE Util
GO
--创建通用的分页存储过程
USE Util
GO
/****** Object: StoredProcedure [dbo].[UP_GeneralPagedQuery_v1] Script Date: 04/03/2014 17:32:07 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO -- Author: DeanZhou
-- Create date: 2013-09-24
-- Description: 通用的分页存储过程(一)
CREATE PROCEDURE [dbo].[UP_GeneralPagedQuery_v1]
@TableName VARCHAR(100) , --表名称:如 MKT.dbo.UV_CouponInfo
@WhereField NVARCHAR(1000) = '' , --筛选条件:如 Status = 1 AND CreateUser = 'admin'
@SelectField NVARCHAR(1500) = '*' , --需要查询的列:如 *
@OrderField NVARCHAR(1000) = '' , --需要进行排序的字段:如 CustomerName desc,StartDate asc,Status desc,id asc
@PageSize INT = 15 , --页面大小:如 15
@PageIndex INT = 1 , --当前页面:如 1
@TotalCount INT = 0 OUT --记录总数:输出值
AS
BEGIN IF @OrderField IS NULL OR @OrderField = ''
BEGIN
SET @OrderField = ' ID '
END IF @WhereField IS NULL OR @WhereField = ''
BEGIN
SET @WhereField = ' WHERE ID > 0 '
END
ELSE
BEGIN
SET @WhereField = ' WHERE ' + @WhereField
END DECLARE @ExceptCount INT = @PageSize * ( @PageIndex - 1 )
DECLARE @TakeCount INT = @PageSize
DECLARE @IsNeedSubQuery INT DECLARE @SqlPreview NVARCHAR(MAX) =
'SELECT @C = COUNT(1) FROM ' + @TableName + ' ' + @WhereField + ';'
+ 'IF @EC < 0 SET @EC = 0 IF @EC >= @C SET @EC = @C;'
+ 'IF @TC < 0 SET @TC = 15 IF (@EC + @TC) > @C SET @TC = @C - @EC;'
+ 'IF @EC > 0 AND @TC > 0 SET @NSQ = 1 ELSE SET @NSQ = 0;' EXEC sp_executesql @SqlPreview,
N'@C INT OUTPUT,@EC INT OUTPUT,@TC INT OUTPUT,@NSQ INT OUTPUT',
@TotalCount OUTPUT, @ExceptCount OUTPUT, @TakeCount OUTPUT, @IsNeedSubQuery OUTPUT DECLARE @MaxOrMin VARCHAR(3) = 'MAX'
DECLARE @DescOrAsc VARCHAR(4) = ''
IF @ExceptCount > @TotalCount / 2
BEGIN
SET @MaxOrMin = 'MIN'
SET @DescOrAsc = 'DESC'
SET @ExceptCount = @TotalCount - @ExceptCount + 1
END DECLARE @SqlQuery NVARCHAR(MAX) =
' DECLARE @T_IDS TABLE (ID INT) '
+ ' IF @NSQ = 1' +
' BEGIN ' +
' SELECT @MD = ' + @MaxOrMin + '(ID) FROM '+
' (SELECT TOP ' + CONVERT(VARCHAR(15), @ExceptCount) + ' ID FROM ' + @TableName + ' ' + @WhereField + ' ORDER BY ' + @OrderField + ')T1;' +
' INSERT INTO @T_IDS '+
' SELECT TOP ' + CONVERT(VARCHAR(15), @TakeCount) + ' ID FROM ' + @TableName + ' ' + @WhereField + ' AND ID > @MD ORDER BY ' + @OrderField +
' SELECT ' + @SelectField + ' FROM ' + @TableName + ' S WHERE ID IN (SELECT ID FROM @T_IDS) ORDER BY ' + @OrderField +
' END ' +
' ELSE' +
' BEGIN ' +
' INSERT INTO @T_IDS SELECT ID FROM (SELECT TOP ' + CONVERT(VARCHAR(15), @TakeCount) + ' ID FROM ' + @TableName + ' ' + @WhereField + ' ORDER BY ' + @OrderField + ')T;' +
' SELECT ' + @SelectField + ' FROM ' + @TableName + ' S WHERE ID IN (SELECT ID FROM @T_IDS) ORDER BY ' + @OrderField +
' END ' EXEC sp_executesql @SqlQuery, N'@MD INT,@NSQ INT', 0, @IsNeedSubQuery END GO --创建测试库
CREATE DATABASE Test
GO --创建测试表
USE [Test]
CREATE TABLE TableTest (ID INT,NAME NVARCHAR(50),CreateDate DATETIME)
GO --插入测试数据
INSERT INTO TableTest
SELECT 1,'dean1',GETDATE() UNION
SELECT 2,'dean2',GETDATE() UNION
SELECT 3,'dean3',GETDATE() UNION
SELECT 4,'dean4',GETDATE()

  打开您的sqlserver,在本地新建查询,并运行上面的代码,会在你的数据库中创建以下内容:

  1. 一个名称为【Util】的数据库,该库下面有一个名为【UP_GeneralPagedQuery_v1】的存储过程,这个存储过程就是通用的分页存储过程。
  2. 一个名称为【Test】的数据库,该库下面有一个名为【TableTest】的表,这个表里面有4条数据

请注意:在执行sql之前确认一下没有重名数据库,以免出错

测试

  新建一个查询,执行下面sql,就完成了分页数据的获取

DECLARE    @TotalCount int
EXEC Util.[dbo].[UP_GeneralPagedQuery_v1]
@TableName = N'Test.dbo.TableTest',
@WhereField = N'ID > 0 AND ID < 100',
@SelectField = N'ID,NAME,CreateDate',
@OrderField = N'NAME ASC,CreateDate DESC',
@PageSize = 2,
@PageIndex = 2,
@TotalCount = @TotalCount OUTPUT SELECT @TotalCount as N'@TotalCount'

 
 

SQLServer通过链接服务器远程删除数据性能问题解决

 

在上一遍文章中介绍了SQLServer通过链接服务器访问Oracle性能问题的解决方法,本文介绍链接服务器下远程删除SQLServer数据的性能问题解决

1. 问题发现

系统中有个功能,需要远程删除SQLServer实例的表数据,删除语句中有where条件,条件中有一个子查询。

该功能前台执行速度非常慢。所以准备调优。

下面为演示代码,未优化前如下:

DELETE
FROM [LINKSERVERNAME].[AdventureWorks2008].[Sales].[SalesOrderDetail]
WHERE SalesOrderDetailID=5
AND EXISTS(SELECT TOP 1 1 FROM [LINKSERVERNAME].[AdventureWorks2008].[Sales].[SalesOrderDetail])

  此时的执行计划如下图:

可以看到执行计划存在一个远程扫描,然后在本地执行筛选。

在远程服务器开启profiler跟踪,部分内容如下图:

可以看到远程服务器开启了一个游标,然后逐行读取数据并返回给调用端。

可以预见性能会非常差,如何避免不带where条件的远程扫描呢?

2. 问题解决

2.1 OpenQuery

使用OpenQuery将delete数据的筛选提交到远程服务器执行。

DELETE
FROM OPENQUERY([LINKSERVERNAME]
,'SELECT *
FROM [AdventureWorks2008].[Sales].[SalesOrderDetail]
WHERE SalesOrderDetailID=5
AND EXISTS(SELECT TOP 1 1 FROM [AdventureWorks2008].[Sales].[SalesOrderDetail])'
)

此时,执行计划如图:

2.2 sp_executesql

将整个delete语句提交到远程执行

DECLARE @sql nvarchar(max)
SELECT @sql ='
DELETE
FROM [AdventureWorks2008].[Sales].[SalesOrderDetail]
WHERE SalesOrderDetailID=5
AND EXISTS(SELECT TOP 1 1 FROM [AdventureWorks2008].[Sales].[SalesOrderDetail])
'
exec [LINKSERVERNAME].[AdventureWorks2008].dbo.sp_executesql @sql

profiler跟踪到的语句如下:

如有不对的地方,欢迎拍砖;如有其他方法,求分享,谢谢!

 
 
分类: SQL Server

分页存储过程实现-SqlServer的更多相关文章

  1. 一个通用的分页存储过程实现-SqlServer(附上sql源码,一键执行即刻搭建运行环境)

    使用前提 查询表必须有ID字段,且该字段不能重复,建议为自增主键 背景 如果使用ADO.NET进行开发,在查询分页数据的时候一般都是使用分页存储过程来实现的,本文提供一种通用的分页存储过程,只需要传入 ...

  2. SqlServer分页存储过程(多表查询,多条件排序),Repeater控件呈现数据以及分页

        存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出 ...

  3. 通用sqlserver分页存储过程

    来自:http://www.cnblogs.com/vagerent/archive/2007/10/17/927825.html 单主键: CREATE PROC P_viewPage    /** ...

  4. SQLserver 的分页存储过程

      -- 1.建立修改学生数据的存储过程 -- 2.建立根据班级Id和学生姓名模糊查询的分页存储过程,要求正确输出总记录数,总页数-- (输入班学生姓名 计算总记录数 计算总页数) -- @name ...

  5. MYSQL分页存储过程及事务处理

    最近给客户做的一小系统是SQLSERVER的数据库,因为特殊原因要切换到MYSQL上去,切换数据库确实让人头疼的,SQLSERVER和MYSQL的存储过程还是有很大差别的,下面是我做切换时转换的MYS ...

  6. EF框架 与 Dapper框架 调用分页存储过程

    1. SqlServer创建存储过程: --创建存储过程 create proc sp_Show ( @index int, --当前页 @size int, --每页大小 @totalcount i ...

  7. 完整的分页存储过程以及c#调用方法

    高效分页存储过程 USE [db] GO /****** 对象: StoredProcedure [dbo].[p_Page2005] 脚本日期: // :: ******/ SET ANSI_NUL ...

  8. 1、SQL可搜索可排序可分页存储过程, 2、范围内的随机时间 适用于sql 2008以上

    -- ============================================= -- Author: 蜘蛛王 -- Create date: 2015-10-29 -- Descri ...

  9. SQL Server 2008 通用分页存储过程

    1.alert USE [数据库名称] GO /****** Object: StoredProcedure [dbo].[dbTab_PagerHelper] Script Date: 08/22/ ...

随机推荐

  1. JQuery插件开发初探——图片轮播

    在熟悉了插件开发的结构以后,自己尝试着做了一个稍微复杂一点的小功能:图片轮播插件. 由于之前使用的一款图片轮播插件,性能不高,页面加载的时候需要载入全部的图片,因此速度很慢. 通过自己做这个小插件,能 ...

  2. [Cocos2d-x]Cocos2d-x 3.2 学习笔记

    获取屏幕大小(Visible) Size visibleSize = Director::getInstance()->getVisibleSize(); Vec2 origin = Direc ...

  3. 用python3.x与mysql数据库构建简单的爬虫系统(转)

    这是在博客园的第一篇文章,由于本人还是一个编程菜鸟,也写不出那些高大上的牛逼文章,这篇文章就是对自己这段时间学习python的一个总结吧. 众所周知python是一门对初学编程的人相当友好的编程语言, ...

  4. STL algorithmi算法s_sorted和is_sorted_until(28)

    is_sort原型: ::is_sorted default (1) template <class ForwardIterator> bool is_sorted (ForwardIte ...

  5. 使用Mockito进行单元测试【2】—— stub 和 高级特性[转]

    一篇中介绍了Mockito的基本信息,现在接着介绍Mockito强大的stub功能 2. Mockito使用实例 5. 对连续的调用进行不同的返回 (iterator-style stubbing) ...

  6. 用Fine Uploader+ASP.NET MVC实现ajax文件上传[代码示例]

    Fine Uploader(http://fineuploader.com/)是一个实现 ajax 上传文件的 Javascript 组件. This project attempts to achi ...

  7. 计算4000000000内的最大f(n)=n值---字符串的问题python实现(五岁以下儿童)

    问题: 写一个函数,计算4 000 000 000 以内的最大的那个f(n)=n的值,函数f的功能是统计全部0到n之间全部含有数字1的数字和.比方:f(13)= 6,由于"1"在& ...

  8. 基于tomcat为了应对高并发模型实现webserver

    在博客上,一个简单的AIOweb来样加工.查看AIO异步处理,依靠操作系统完成IO操作Proactor处理模型确实很强大,它可以实现高并发.高响应server一个很好的选择,但在tomcat中间con ...

  9. 设置CentOS开机连接网络 Centos 开机启动网卡的设置方法

    我们开机网卡不能启动所以只能使用 ifup eth0 (eth0指的网卡) 来启动了,但是每一次都这样感觉不方便希望开机自动启动网卡 后来百度搜索了一下发现可以通过修改网卡( ifcfg-eth0)参 ...

  10. IOS发展--他们控制的定义

    有没有这样的要求,,自定义panel,里面放几个控件,在多个页面中使用此panel. 有三个观点来解决这个问题: 1.自己继承UIView写一个类,在它是在代码的形式加入需要控制.完成布局. 2.使用 ...