一个通用的分页存储过程实现-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源码&测试环境搭建

  1. --创建Util
  2. CREATE DATABASE Util
  3. GO
  4. --创建通用的分页存储过程
  5. USE Util
  6. GO
  7. /****** Object: StoredProcedure [dbo].[UP_GeneralPagedQuery_v1] Script Date: 04/03/2014 17:32:07 ******/
  8. SET ANSI_NULLS ON
  9. GO
  10. SET QUOTED_IDENTIFIER ON
  11. GO
  12.  
  13. -- Author: DeanZhou
  14. -- Create date: 2013-09-24
  15. -- Description: 通用的分页存储过程(一)
  16. CREATE PROCEDURE [dbo].[UP_GeneralPagedQuery_v1]
  17. @TableName VARCHAR(100) , --表名称:如 MKT.dbo.UV_CouponInfo
  18. @WhereField NVARCHAR(1000) = '' , --筛选条件:如 Status = 1 AND CreateUser = 'admin'
  19. @SelectField NVARCHAR(1500) = '*' , --需要查询的列:如 *
  20. @OrderField NVARCHAR(1000) = '' , --需要进行排序的字段:如 CustomerName desc,StartDate asc,Status desc,id asc
  21. @PageSize INT = 15 , --页面大小:如 15
  22. @PageIndex INT = 1 , --当前页面:如 1
  23. @TotalCount INT = 0 OUT --记录总数:输出值
  24. AS
  25. BEGIN
  26.  
  27. IF @OrderField IS NULL OR @OrderField = ''
  28. BEGIN
  29. SET @OrderField = ' ID '
  30. END
  31.  
  32. IF @WhereField IS NULL OR @WhereField = ''
  33. BEGIN
  34. SET @WhereField = ' WHERE ID > 0 '
  35. END
  36. ELSE
  37. BEGIN
  38. SET @WhereField = ' WHERE ' + @WhereField
  39. END
  40.  
  41. DECLARE @ExceptCount INT = @PageSize * ( @PageIndex - 1 )
  42. DECLARE @TakeCount INT = @PageSize
  43. DECLARE @IsNeedSubQuery INT
  44.  
  45. DECLARE @SqlPreview NVARCHAR(MAX) =
  46. 'SELECT @C = COUNT(1) FROM ' + @TableName + ' ' + @WhereField + ';'
  47. + 'IF @EC < 0 SET @EC = 0 IF @EC >= @C SET @EC = @C;'
  48. + 'IF @TC < 0 SET @TC = 15 IF (@EC + @TC) > @C SET @TC = @C - @EC;'
  49. + 'IF @EC > 0 AND @TC > 0 SET @NSQ = 1 ELSE SET @NSQ = 0;'
  50.  
  51. EXEC sp_executesql @SqlPreview,
  52. N'@C INT OUTPUT,@EC INT OUTPUT,@TC INT OUTPUT,@NSQ INT OUTPUT',
  53. @TotalCount OUTPUT, @ExceptCount OUTPUT, @TakeCount OUTPUT, @IsNeedSubQuery OUTPUT
  54.  
  55. DECLARE @MaxOrMin VARCHAR(3) = 'MAX'
  56. DECLARE @DescOrAsc VARCHAR(4) = ''
  57. IF @ExceptCount > @TotalCount / 2
  58. BEGIN
  59. SET @MaxOrMin = 'MIN'
  60. SET @DescOrAsc = 'DESC'
  61. SET @ExceptCount = @TotalCount - @ExceptCount + 1
  62. END
  63.  
  64. DECLARE @SqlQuery NVARCHAR(MAX) =
  65. ' DECLARE @T_IDS TABLE (ID INT) '
  66. + ' IF @NSQ = 1' +
  67. ' BEGIN ' +
  68. ' SELECT @MD = ' + @MaxOrMin + '(ID) FROM '+
  69. ' (SELECT TOP ' + CONVERT(VARCHAR(15), @ExceptCount) + ' ID FROM ' + @TableName + ' ' + @WhereField + ' ORDER BY ' + @OrderField + ')T1;' +
  70. ' INSERT INTO @T_IDS '+
  71. ' SELECT TOP ' + CONVERT(VARCHAR(15), @TakeCount) + ' ID FROM ' + @TableName + ' ' + @WhereField + ' AND ID > @MD ORDER BY ' + @OrderField +
  72. ' SELECT ' + @SelectField + ' FROM ' + @TableName + ' S WHERE ID IN (SELECT ID FROM @T_IDS) ORDER BY ' + @OrderField +
  73. ' END ' +
  74. ' ELSE' +
  75. ' BEGIN ' +
  76. ' INSERT INTO @T_IDS SELECT ID FROM (SELECT TOP ' + CONVERT(VARCHAR(15), @TakeCount) + ' ID FROM ' + @TableName + ' ' + @WhereField + ' ORDER BY ' + @OrderField + ')T;' +
  77. ' SELECT ' + @SelectField + ' FROM ' + @TableName + ' S WHERE ID IN (SELECT ID FROM @T_IDS) ORDER BY ' + @OrderField +
  78. ' END '
  79.  
  80. EXEC sp_executesql @SqlQuery, N'@MD INT,@NSQ INT', 0, @IsNeedSubQuery
  81.  
  82. END
  83.  
  84. GO
  85.  
  86. --创建测试库
  87. CREATE DATABASE Test
  88. GO
  89.  
  90. --创建测试表
  91. USE [Test]
  92. CREATE TABLE TableTest (ID INT,NAME NVARCHAR(50),CreateDate DATETIME)
  93. GO
  94.  
  95. --插入测试数据
  96. INSERT INTO TableTest
  97. SELECT 1,'dean1',GETDATE() UNION
  98. SELECT 2,'dean2',GETDATE() UNION
  99. SELECT 3,'dean3',GETDATE() UNION
  100. SELECT 4,'dean4',GETDATE()

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

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

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

测试

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

  1. DECLARE @TotalCount int
  2. EXEC Util.[dbo].[UP_GeneralPagedQuery_v1]
  3. @TableName = N'Test.dbo.TableTest',
  4. @WhereField = N'ID > 0 AND ID < 100',
  5. @SelectField = N'ID,NAME,CreateDate',
  6. @OrderField = N'NAME ASC,CreateDate DESC',
  7. @PageSize = 2,
  8. @PageIndex = 2,
  9. @TotalCount = @TotalCount OUTPUT
  10.  
  11. SELECT @TotalCount as N'@TotalCount'

 
 

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

 

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

1. 问题发现

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

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

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

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

  此时的执行计划如下图:

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

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

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

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

2. 问题解决

2.1 OpenQuery

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

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

此时,执行计划如图:

2.2 sp_executesql

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

  1. DECLARE @sql nvarchar(max)
  2. SELECT @sql ='
  3. DELETE
  4. FROM [AdventureWorks2008].[Sales].[SalesOrderDetail]
  5. WHERE SalesOrderDetailID=5
  6. AND EXISTS(SELECT TOP 1 1 FROM [AdventureWorks2008].[Sales].[SalesOrderDetail])
  7. '
  8. 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. 一个由proguard与fastJson引起的血案(转)

    更新微信sdk导致ComposeData中的内部类ComposeDataSender方法被混淆 根本原因,fastjson使用姿势不对. 问题描述: 一个发件人列表里,应当呈现的数据(这里命名为Com ...

  2. Oracle语句优化1

    Oracle语句优化1 优化就是选择最有效的方法来执行SQL语句.Oracle优化器选择它认为最有效的     方法来执行SQL语句.         1. IS   NULL和IS   NOT   ...

  3. Swift使用单个案件管理FMDB数据库

    下班... 抢 我曾经Swift使用单一个案管理FMDB数据库的方法共享出来: // Created by 秦志伟 on 14-6-12. import UIKit class ZWDBManager ...

  4. CSS浏览器兼容性问题集()两

    11.非常适合    高度适合于被改变时所述内目标高度的外层的高度不能自己主动调节,尤其是排队对象时margin 要么paddign 时. 例:   #box {background-color:#e ...

  5. mysql只导出表结构或数据

    唯一的非导电结构指南数据 mysqldump -t 数据库名称 -uroot -p > xxx.sql 指南结构不仅指导数据 mysqldump    --opt -d  数据库名 -u -p ...

  6. WebService到底是什么? [转]

    一.序言 大家或多或少都听过WebService(Web服务),有一段时间很多计算机期刊.书籍和网站都大肆的提及和宣传WebService技术,其中不乏很多吹嘘和做广告的成分.但是不得不承认的是Web ...

  7. Struts1——离BeanUtils看struts其原理1

    在Struts中非常典型的特点就是使用了ActionForm来搜集表单数据,可是搜集到的表单数据所有都是String类型的.假设我们直接拿来使用我们会面临一个非常麻烦的问题就是频繁的类型装换. Str ...

  8. MySQL汇总数据

    汇总数据 有时,数据本身是不上台面的操作数据表.但在摘要表中的数据.例如 数据的一列的平均值.极大值.至少值等一下. 对于这些频繁使用的数据的处理的概要,MySQL它提供了一个函数来处理. SQL聚集 ...

  9. TFTP server组态

    TFTP server组态 2014-10-31北京海淀区  张俊浩 一.TFTP(Trivial File Transfer Protocol,简单文件传输协议或称小型文件传输协议) 是一种简化的文 ...

  10. 【百度地图API】如何制作多途经点的线路导航——驾车篇

    原文:[百度地图API]如何制作多途经点的线路导航--驾车篇 摘要: 休假结束,酸奶小妹要从重庆驾车去北京.可是途中要去西安奶奶家拿牛奶饼干呢!用百度地图API,能不能帮我实现这个愿望呢? ----- ...