一个通用的分页存储过程实现-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. 携程Java工程师——一道面向对象面试选择题(转)

    public class Base { private String baseName = "base"; public Base() { callName(); } public ...

  2. 简单的工具LogUtil、Toast

    简单的工具LogUtil.Toast     能够用了 import android.content.Context; import android.util.Log; import android. ...

  3. ORACLE 动态注册和静态注册的区别(转)

    1, oracle 10g 用netca方式建立的都默认为动态注册方式2,如果想改为静态注册的方式则在listener.ora 中加入如下内容即可 SID_LIST_LISTENER = (SID_L ...

  4. oracle当需要commit

    今天oracle的SQL plus 运行该删除和查询操作,然后PL/SQL还运行查询.相同的句子,结果是不一样的.我郁闷很大,然后,突然想到这可能对双方造成由数据不一致,为什么不一致呢.就是没用com ...

  5. android账号与同步之发起同步

    上一篇博文我介绍了账号与同步的同步实现过程,当中提供了一个工系统进程调用的服务,那么这个服务究竟是怎么被启动和使用的呢?这篇博文我就大体梳理一下启动过程. 事实上作为一个一般开发者,我们仅仅要知道要想 ...

  6. OWIN轻量型框架介绍

    OWIN轻量型框架介绍 阅读目录 引言 框架的特色 如何启动 各项功能 静态路由的3种写法 伪静态路由的支持 处理Form表单提交的文件 流式处理Post请求的数据 多种请求类型自动识别 响应处理 请 ...

  7. 承诺c指针 (1)指针是地址

    (1)是地址 首先明白一个观点:指针就是地址.这是理解指针的起始一步. 直观感受下.变量的地址 int main() { int foo; int *foo_p; foo = 5; foo_p = & ...

  8. 开始折腾cocos2d-x,使用批处理来创建项目

    开始服用的时间来学习cocos2d-x该,尽管C和C++另外不咋.只是学习和记忆可能是更深层次的,现在发展: so从今天开始正式决定学会与自己的业余时间折腾吧,仅这51什么.昨天,在开发环境中建,Vi ...

  9. mac_开启ftp并访问

    [启动&关闭] mac下一般用smb服务来进行远程文件访问,但要用FTP的话,高版本的mac os默认关掉了,可以用如下命令打开: sudo -s launchctl load -w /Sys ...

  10. Jquery Jqprint—随着Jquery Jqprint实现网页打印

    研究关于利用空闲时间今天Jquery Jqprint插入,用这个Jquery脚本就可以实现轻松打印指定的页面内容功能区: 样品A: <!DOCTYPE html PUBLIC "-// ...