存储过程(stored procedure)有时也称sproc,它是真正的脚本,更准确地说,它是批处理(batch),但都不是很确切,它存储与数据库而不是单独的文件中。数据库
存储过程当中有输入参数,输出参数以及返回值等。缓存
1、建立存储过程安全
建立存储过程的方法和建立数据库中任何其余对象同样,除了他使用AS关键字外。存储过程的基本语法以下:ide
CREATEPROCEDURE|PROC<sproc name>[ [schema.]<data type>[VARYING][=][OUT[PUT]] [READONLY][, [schema.]<data type>[VARYING][=][OUT[PUT]] [READONLY][,... ... ]] [WITH RECOMPILE | ENCRYPTION | [EXECUTE AS { CALLER | SELF | OWNER | <'user name'>}]AS<code>| EXTERNAL NAME <assembly name>.<assembly class>.<method>工具
在语法中,PROC是PROCEDURE的缩写,两个选项的意思同样。性能
在对存储过程命名完以后,接着是参数列表。参数是可选的。优化
关键字AS其后就是实际的代码。spa
简单的存储过程示例:设计
CREATEPROC spPerson ASSELECT*FROM Personcode
执行存储过程:
EXEC spPerson
查看结果:
2、ALTER修改存储过程
ALTER PROC和CREATE PROC的区别以下:
ALTER PROC指望找到一个已有的存储过程,而CREATE则不是。
ALTER PROC保留了存储过程上已经创建的任何权限。它在系统对象中保留了对象Id并容许保留依赖关系。例如,若是过程A调用过程B,若是删除并重建B,那么就不能在看到这二者间的依赖关系。若是使用ALTER,则依赖关系仍然存在。
ALTER PROC在可能调用被修改的存储过程的其余对象上保留了任何依赖信息。
示例:
ALTERPROC spPerson ASSELECT*FROM Person WHERE Id =45
3、删除存储过程
删除存储过程的语法最简单:
DROPPROC|PROCEDURE<sproc name>[;]
这样就完成了存储过程的删除。
4、参数化
若是存储过程没有办法接受一些数据,告诉其要完成的任务,则在大多数状况下,存储过程不会有太大帮助。例如,要删除一条数据,但却不指定Id,则存储过程也不知道要删除哪条,因此使用输入参数很是有必要。
一、声明参数
声明参数须要如下2到4部分的信息:
名称
数据类型
默认值
方向
其语法以下所示:
@parameter_name[AS] datatype [=default|NULL][VARYING][OUTPUT | OUT]
对于名称,有一组简单的规则。首先,它必须以@符号(和变量同样)开始。此外,除了不能内嵌空格外,其规则与普通变量规则相同。
数据类型和名称同样,必须像变量那样声明,采用SQL Server内置的或用户自定义的数据类型。
声明须要类型时须要注意,当声明CURSOR类型参数时,必须也使用VARYING和OUTPUT选项。同时,OUTPUT能够简写为OUT。
在默认值方面,参数与变量不一样。对于一样的状况,变量通常初始化为NULL值,而参数不是。事实上,若是不提供默认则,则会假设参数是必须的,而且当调用存储过程时须要提供一个初始值。
一个须要传入参数的存储过程示例:
CREATEPROC spName @Namenvarchar(50) ASSELECT Name FROM Person WHERE Name LIKE@Name+'%';
执行存储过程:
EXEC spName '酒';
显示结果以下:
二、提供默认值
为了使参数是可选的,必须提供默认值。方法是在数据类型后在逗号以前添加"="符号和做为默认值的值。这样,存储过程的用户尅有决定对此参数不提供值或是提供他们本身的值。
建立一个存储过程以下:
CREATEPROC spName @Namenvarchar(50) =NULLASIF@NameISNOTNULLSELECT*FROM Person WHERE NAME =@NameELSESELECT*FROM Person WHERE Id =45
执行以下语句:
EXEC spName EXEC spName '如意刀狼'
输出结果以下:
三、输出参数
下面来看看一个得到OUTPUT参数的存储过程:
CREATEPROC InsertPerson @Idint OUTPUT --必须注明为OUTPUTASINSERTINTO Person VALUES('刘备',22,190,'不详','未婚','幼儿园','不详',4999999) SET@Id=@@IDENTITY
执行存储过程:
DECLARE@Idint --实际上,调用时名称能够不一样,例如也能够为@Num,@i等等。EXEC InsertPerson @Id OUTPUT --注意此处也要有OUTPUTSELECT@Id
显示结果以下:
对于存储过程自己以及调用脚本对它的使用,须要注意如下几点:
对于存储过程声明中的输出参数,须要使用OUTPUT关键字。
和声明存储过程时同样,调用存储过程时,必须使用OUTPUT关键字。这样就对SQL Server做了提早通知,告诉它参数所须要的特殊处理。但须要注意的是,若是忘记包含OUTPUT关键字,不会产生运行时错误,可是输出的值不会传入变量中(变量极可能是NULL)。
赋值给输出结果的变量不须要和存储过程当中的内部参数拥有相同的名称。
EXEC(或EXECUTE)关键字是必须的,由于对存储过程的调用并非批处理要作的第一件事(若是存储过程的调用是批处理的第一件事,则能够不使用EXEC)。
5、返回值
返回值的用途很是普遍,例如,返回数据,标识值或是存储过程影响的行数等等。而其实际做用是返回值可用来肯定存储过程执行的状态。
事实上,无论是否提供返回值,程序都会收到一个返回值。SQL Server默认会在完成存储过程时自动返回一个0值。
为了从存储过程向调用代码传递返回值,只须要使用RETURN语句。
RETURN[]
要特别注意的是:返回值必须是整数。
关于RETURN语句,最重要的是知道它是无条件地从存储过程当中退出的。不管运行到存储过程的哪一个位置,在调用RETURN语句以后将不会执行任何一行代码。
这里的无条件,并非说不管执行到代码的何处都将执行RETURN语句。相反,能够再存储过程当中有多个RETURN语句。只有当代码的标准条件结构发出命令的时候,才会执行这些RETURN语句。一旦发生,就不能再退回了。
建立一个存储过程以下:
CREATEPROC spTestReturns ASDECLARE@MyMessagenvarchar(50); DECLARE@MyOtherMessagenvarchar(50); SELECT@MyMessage='第一个RETURN'; PRINT@MyMessage; RETURN; SELECT@MyOtherMessage='第二个RETURN'; PRINT@MyOtherMessage; RETURN;
执行存储过程,输出以下:
为了能捕获RETURN语句的值,须要在EXEC语句中把值赋给变量。例如:
DECLARE@Returnint EXEC@Return= spTestReturns SELECT@Return
输出以下:
虽然简单可是还不错。当运行时,能够看到RETURN语句倒是在运行其余代码前终止了代码运行。
若是老是返回0,那么执行成不成功都不知道,那么咱们如今来改写下上面的存储过程,让其返回一个指定的值,以指示执行状态。
CREATEPROC spTestReturns ASDECLARE@MyMessagenvarchar(50); DECLARE@MyOtherMessagenvarchar(50); SELECT@MyMessage='第一个RETURN'; PRINT@MyMessage; RETURN100; --将这里改为返回100SELECT@MyOtherMessage='第二个RETURN'; PRINT@MyOtherMessage; RETURN;
执行以后,显示结果以下:
6、存储过程的优缺点
存储过程的主要优势包括如下几个方面:
使得须要过程式动做的进程可调用
安全性
性能
一、建立可调用的进程
不少人并无意识到要充分使用存储过程,使其做为实现安全性的工具。和视图相似,能够建立一个返回记录集的存储过程而不用赋予用户访问底层数据表的权限。赋予某人执行一个存储过程的权限意味着他们能够在该存储过程当中执行任何动做。不过要假设动做是在存储过程的上下文中执行的。
二、存储过程和性能
通常来讲,存储过程有助于系统性能的提升。可是,若是设计的存储过程缺少只能,那么它会使在其建立的进程变得很是缓慢。
存储过程的运行示意图以下:
首先运行CREATE PROC过程。这回解析查询以确保会实际运行这些代码。它与直接运行脚本的区别在于CREATE PROC命令能够利用所谓的延迟名称解析。延迟名称解析能够忽略一些对象还不存在的事实。
在建立了存储过程后,它将等待第一次执行。在那时,存储过程被优化,而查询计划被编译而且缓存到系统上。后续几回运行该存储过程时,除非经过使用WITH RECOMPILE选项指定,不然都会使用缓存的查询计划而不是建立一个新的查询计划。这意味着每次使用该存储过程时,存储过程都会跳过不少优化和编译工做。节省的确切时间取决于批处理的复杂性,批处理中表的大小,以及每一个表上索引的数量。一般,节省的时间不是不少。但对于大多数场景来讲多是1秒或更少-但经过百分比能够计算出此区别(1秒比2秒快了100%)。当须要进行屡次调用时或针对循环的状况,这一区别会变得更明显。
三、存储过程的不利方面
对于存储过程的不利之处要认识到的最重要的一点事,除非手动地干预(使用WITH RECOMPILE选项),不然只会在第一次运行存储过程的时候,或者当查询所涉及的表更新了统计信息时,才对存储过程进行优化。
这种"一次优化,屡次使用"的策略节省了存储过程的时间,可是该策略也是一把双刃剑。若是查询是动态的(便是在使用EXEC命令时创建的),那么只会在第一次运行时对存储过程进行优化,可是会发现之后不再这样了。简而言之,可能会使用错误的计划。
四、WITH RECOMPILE选项
能够利用存储过程提供的安全性代码和代码封装方面的好处,但仍是忽略了预编译代码方面的影响。能够回避未使用正确的查询计划的问题,由于能够确保为特定一次运行建立新的计划。方法就是使用WITH RECOMPILE选项。
使用该选项的方式有两种:
一、能够在运行时包含WITH RECOMPILE。
EXEC spMySproc '1/1/2004'WITH RECOMPILE
这告诉SQL Server抛弃已有的执行计划而且建立一个新的计划-但只是这一次。也就是说,只是此次使用WITH RECOMPILE选项来执行存储过程。
也能够经过在存储过程当中包含WITH RECOMPILE选项来使之变得更持久。若是使用这种方式,则在CREATE PROC或ALTER PROC语句中的AS语句前添加WITH RECOMPILE选项便可。
若是经过该选项建立存储过程,那么不管在运行时选择了其余什么选项,每次运行存储过程都会从新编译它。