存储过程参数传递

http://www.cnblogs.com/double-K/p/6203202.html

前言

  很多人认为数据库其实很简单,也没什么大深入的细节去研究,但是真正的一些细节问题决定着你的是否是专家。

  本文主要讲述一下存储过程参数传递的一些小细节,很多人知道参数嗅探,本例也可以理解成参数嗅探的威力加强版++

小例子

 1 ---创建测试表
 2 SELECT IDENTITY(INT,1,1) AS RID,
 3 * INTO TB1
 4 FROM sys.all_columns
 5 GO
 6 ---模拟大量数据
 7 INSERT INTO TB1
 8 SELECT *
 9 FROM sys.all_columns
10 GO 100
11
12
13
14 --在 user_type_id列 创建一个索引
15 CREATE NONCLUSTERED INDEX [NonClusteredIndex-20160625-164531] ON [dbo].[TB1]
16 (
17     [user_type_id] ASC
18 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
19 GO
20
21 --开启IO统计
22 set statistics io on
23
24 --测试查询执行计划
25 select * from tb1 where user_type_id = 10

注:本例中,语句的执行应该走索引seek + key look up

测试一

 1 --测试1:使用定义变量,把参数值传递给变量
 2
 3 create PROCEDURE dbo.USP_GetData
 4 (
 5   @PID INT
 6 )
 7 AS
 8 BEGIN
 9 DECLARE @ID INT
10 SET @ID= @PID
11 SELECT *
12 FROM TB1
13 WHERE user_type_id = @ID
14 END
15 GO
16 EXEC dbo.USP_GetData @PID=10

结论:如果在存储过程中定义变量,并为变量SET赋值,该变量的值无法为执行计划提供参考(即执行计划不考虑该变量),将会出现预估行数和实际行数相差过大导致执行计划不优的情况

测试二

 1 ---测试2 : 对参数进行运算
 2 create PROCEDURE dbo.USP_GetData2
 3 (
 4   @PID INT
 5 )
 6 AS
 7 BEGIN
 8 SET @[email protected]
 9 SELECT*
10 FROM TB1
11 WHERE user_type_id = @PID
12 END
13 GO
14 EXEC dbo.USP_GetData2 @PID=11

结论:如果在存储过程中使用SET为存储过程参数重新赋值,执行计划仍采用执行时传入的值来生成执行计划。

测试三

 1 --测试3 :对参数行进拼接
 2
 3 create PROCEDURE dbo.USP_GetData3
 4 (
 5 @PID INT
 6 )
 7 AS
 8 BEGIN
 9 DECLARE @ID INT
10 set @ID = 2
11 SET @PID = @ID + @PID
12 SELECT *
13 FROM TB1
14 WHERE user_type_id = @PID
15 END
16 GO
17 EXEC dbo.USP_GetData3 @PID= 8

结论:如果在存储过程中使用新定义的变量与传入参数拼接重新赋值,执行计划仍采用执行时传入的值来生成执行计划。

测试四

 1 --测试4 : 对变量进行运算
 2 create PROCEDURE dbo.USP_GetData4
 3 (
 4   @PID INT
 5 )
 6 AS
 7 BEGIN
 8 SELECT *
 9 FROM TB1
10 WHERE user_type_id = @PID+ 2
11 END
12 GO
13 EXEC dbo.USP_GetData4 @PID=8

结论:虽然传入参数在传入后被修改,但是生成执行计划时仍使用传入时的值

测试五

 1 --测试5 :对变量进行复杂运算
 2 create PROCEDURE dbo.USP_GetData5
 3 (
 4 @PID INT
 5 )
 6 AS
 7 BEGIN
 8 SELECT *
 9 FROM TB1
10 WHERE user_type_id = @PID+ CAST(RAND()*600 AS INT)
11 END
12 GO
13 EXEC dbo.USP_GetData5 @PID=8
14 GO

结论:对参数做复杂运算,无法获得准确的值,因此不能准确地预估行数,也不能生成合理的执行计划

测试六

 1 --测试6 : 复杂运算使用变量拼接
 2 create PROCEDURE dbo.USP_GetData6
 3 (
 4 @PID INT
 5 )
 6 AS
 7 BEGIN
 8 DECLARE @ID INT
 9 set @ID = CAST(RAND()*600 AS INT)
10 SET @PID = @ID + @PID
11 SELECT *
12 FROM TB1
13 WHERE user_type_id = @PID
14 END
15 GO
16 EXEC dbo.USP_GetData6 @PID=8
17 GO

结论:针对测试五可以使用参数拼接的方式,以便准确地预估行数,使用正确的执行计划

总结

  技术支持做了比较长的时间了,遇到了很多很多坑,在这些坑中不断反思,慢慢成长!不要说什么数据库更优秀,不要说我们海量数据库需要什么什么高端的技术,其实解决问题的关键只是那么一点点的基础知识。

  注:本例中还有另外一种情况就是查询的数据量很大,那么本身走全表扫描是最优计划,而由于参数传递的问题错误的走了index seek + key look up 道理是一样的。

--------------博客地址-----------------------------------------------------------------------------

原文地址: http://www.cnblogs.com/double-K/

如有转载请保留原文地址! 

时间: 2024-10-16 17:13:20

存储过程参数传递的相关文章

oracle 存储过程详细介绍(创建,删除存储过程,参数传递等)

这篇文章主要介绍了oracle 创建,删除存储过程,参数传递,创建,删除存储函数,存储过程和函数的查看,包,系统包等相关资料,需要的朋友可以参考下 oracle 创建,删除存储过程,参数传递,创建,删除存储函数,存储过程和函数的查看,包,系统包 认识存储过程和函数 存储过程和函数也是一种PL/SQL块,是存入数据库的PL/SQL块.但存储过程和函数不同于已经介绍过的PL/SQL程序,我们通常把PL/SQL程序称为无名块,而存储过程和函数是以命名的方式存储于数据库中的.和PL/SQL程序相比,存储

SQL Server--你可能不知道的技术细节:存储过程参数传递的影响

前言 很多人认为数据库其实很简单,也没什么大深入的细节去研究,但是真正的一些细节问题决定着你的是否是专家. 本文主要讲述一下存储过程参数传递的一些小细节,很多人知道参数嗅探,本例也可以理解成参数嗅探的威力加强版++ 小例子 ---创建测试表 SELECT IDENTITY(INT,1,1) AS RID, * INTO TB1 FROM sys.all_columns GO ---模拟大量数据 INSERT INTO TB1 SELECT * FROM sys.all_columns GO 10

oracle的存储过程和函数(PL/SQL)

czmmiao 存储过程概述 存储过程是子程序的一种类型,能够完成一些任务,作为schema对象存储于数据库.是一个有名字的PL/SQL代码块,支持接收或不接受参数,同时也支持参数输出.一个存储过程通常包含定义部分,执行部分,Exception部分,可以被其他子程序调用,也可以被重用.过程定义CREATE [OR REPLACE]PROCEDURE procedure_name[(argument_name [IN | OUT | IN OUT] argument_type)]AS | ISBE

mysql 存储过程错误调试记录

 mysql存储过程错误调试记录 公司平台在mysql数据库上运行,一些存储过程报错,调试过程痛苦,记录错误及解决办法,供参考. 调试环境:dbForge Studio for MySQL 6.1版本,试用版: 1.BIZ_GET_ORGAN_BY_CONDITION 问题1:提示递归调用错误,递归次数太多:根据业务设置,最大255: [email protected]@max_sp_recursion_depth = 10; 常见如乱码造成导致条件失效,出现死循环: 问题2:变量的内容是乱

Java复习之数据库编程

一.JDBC概述 1. JDBC的主要作用(Java Database Connectivity,Java数据库连接) 提供了一种与平台无关的用于执行SQL语句的标准Java API,由一组用Java语言编写的类和接口组成 JDBC 驱动分类: JDBC-ODBC桥驱动 JDBC本地驱动 JDBC网络驱动 本地协议纯JDBC驱动 2. JDBC的主要操作接口 java.sql.DriverManager java.sql.Connection java.sql.Statement java.sq

Msql浅析-基础命令(二)

篇幅简介 一.Msql数据类型 1.整型 tinyint,  占 1字节 ,有符号: -128~127,无符号位 :0~255 smallint, 占 2字节 ,有符号: -32768~32767无符号位 :0~65535 mediumint 占 3字节 ,有符号: -8388608~8388607,无符号位:0~16777215: int, 占 4字节 ,有符号: -2147483648~2147483647,,无符号位 无符号位 :0~4 284967295 bigint, bigint,b

SQL实现递归及存储过程中In()参数传递解决方案[转]

SQL实现递归及存储过程中In()参数传递解决方案 1.SQL递归 在SQL Server中,我们可以利用表表达式来实现递归算法,一般用于阻止机构的加载及相关性处理. -->实现: 假设OrganiseUnit(组织机构表)中主要的三个字段为OrganiseUnitID(组织机构主键ID).ParentOrganiseUnitID(组织机构父ID).OrganiseName(组织机构名称) ? 1 2 3 4 5 6 7 [sql] with organise as (select * from

将xml作为输入参数传递给存储过程

1 查看存储过程的方式 exec sp_helptext 'GetTrackingFeedLogByMaxId' select definition from sys.sql_modules where object_id=(OBJECT_ID(N'GetTrackingFeedLogByMaxId')) 2 在调用有输入参数的存储过程时必须包含参数,除非参数有默认值 3 系统存储过程sp_xml_preparedocument和OPENXML函数来操作传入的xml文档 DECLARE @XML

MySQL存储过程单参数或多参数传递

MySQL开发的存储过程几乎都需要参数.这些参数使存储过程更加灵活和有用. 在MySQL中,参数有三种模式:IN,OUT或INOUT. 1,单参数 in DELIMITER $$USE dc3688$$CREATE PROCEDURE GetOfficeByCountry(IN countryName VARCHAR(255))BEGINSELECT * FROM officesWHERE country = countryName;END$$ DELIMITER ; 2,多参数 (in out