sp_prepare与语句句柄

2024-04-04 05:58
文章标签 句柄 语句 sp prepare

本文主要是介绍sp_prepare与语句句柄,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

长久以来一直都在处理别人的产品跟数据库,使用事件探查器来跟踪代码执行情况是我最常用的解析别人产品的方式,不过昨天在搞怡软产品的时候却发现这招不好使,事件探查器中根本看不到一句数据库SQL语句,所有的操作全部都用语句句柄来做了,看到最多的就是 exec sp_execute 11,1,即便在事件探查器中添加参数SP:StmtStaring,SP:StmtCompleted,也没有结果,原因是在处理过程中检测到了Password,探查器给替换了文本。真是万恶,这样就起到了隐藏代码的目的。

   有些地方可以查到使用了sp_prepare来预编译SQL语句,之后在执行语句时只需要调用句柄就可以,而非sp_executesql那样每次调用都必须传递语句和变量。这样处理在多次调用同一语句的情况下,执行速度和代码简洁度都要好一些,不过除此之外暂时没有感觉到有其他好处。

以下是李维的书上的测试:从别的地方看到的,留下来,有空的时候研究一下。
是测试UnPrepared的TADOQuery组件、Prepared的TADOQuery组件以
及TADOStoredProc组件执行新增数据的范例应用程序的执行画面。由于这个范例
应用程序使用了相同的方式新增大量的数据,因此我们可以通过它来测试
UnPrepared的TADOQuery组件、Prepared的TADOQuery组件以及TADOStoredProc
组件相对的执行效率。
执行这个范例应用程序时,也激活了MSSQLProfiler来观察这三个不同的组
件在同样新增数据时执行的行为是什么?下面的数据是UnPrepared的TADOQuery
组件执行新增数据时MS SQL Profiler 观察到的Action Query :
sp_executesql N'insert into ADOTestDatas
(ID, Name, Phone, Address, Salary, EDate)
values
(@P1, @P2, @P3, @P4, @P5, @P6)
', N'@P1 varchar(10),@P2 varchar(10),@P3 varchar(13),@P4
varchar(50),@P5 float,@P6 datetime', 'K334646237', 'dbuuaiudlo',
'5388648427081',
'icwwoapxxxabukwhbciietruytkpftlgnpqqsclcsprmnhpkxu' ,
99572.479999999996, '20000625 15:27:19:000'
. . .
当应用程序使用UnPrepared的TADOQuery组件新增数据时,对于每一笔新增
的数据,ADO驱动程序都会执行一次上面的SQL命令。从这个观察的结果我们可
以看到,在使用UnPrepared的TADOQuery组件时,MSSQLServer会将每一笔新增
数据的ActionQuery编译成一个暂时的存储过程,再执行它。因此,如果新增了
1000笔数据,那么Action Query 便被编译了1000次。
下面的数据则是当Prepared的TADOQuery组件执行时MS SQL Profiler 观察到
的结果。可以看到,当使用Prepared的TADO Query组件时,MSSQL Server 只会先
编译Action Query 一次成为一个暂时的存储过程:
declare @P1 int
set @P1=NULL
exec sp_prepare @P1 output, N'@P1 varchar(10),@P2 varchar(10),@P3
varchar(13),@P4 varchar(50),@P5 float,@P6 datetime', N'insert into
ADOTestDatas
(ID, Name, Phone, Address, Salary, EDate)
values
(@P1, @P2, @P3, @P4, @P5, @P6)
', 1
select @P1
而当Prepared的TADOQuery组件新增每一笔数据时,MSSQL Server 只是执行
刚才编译的暂时存储过程,并且只把参数传递给这个暂时的存储过程:
sp_execute 1, 'Z252651567', 'yexoxpwyck', '6683134408672',
'ozerprmgkijeypizrftswouqbmekuxlasrgubzmciwqtuqmjvx' ,
13449.690000000001, '20000625 15:27:36:000'
至于范例应用程序使用TADOStoredProc组件执行新增数据时,它的Action
Query和使用Prepared的TADOQuery组件几乎是一样的。只是TADOStoredProc组件
连第一次编译暂时存储过程的步骤也不用,因为TADOStoredProc组件已经连接了
一个已经存在的存储过程,因此只需要传递参数给这个已经存在的存储过程执行
新增数据的工作即可。
从上面的讨论之中你可以了解,对于应用程序中经常执行的SQL命令而言,使
用Prepared的TADOQuery会比使用UnPrepared的TADOQuery来得快速,因为
Prepared的TADOQuery可以省去每次都需要数据源编译SQL命令的步骤。而Prepared
的TADOQuery和TADOStoredProc的执行效率应该差不多,TADOStoredProc会比
Prepared的TADOQuery来得快一点。
下面的表格便是这三种组件在执行新增数据时的结果:
新增数据(1000笔)新增数据(5000笔)
UnPrepared4.46628
Prepare3.58526.117
Stored Procedure 3.82528.561
上面的执行结果也证明了UnPrepared的TADOquery的执行效率比Prepared的
TADOQuery和TADOStoredProc低一些。
下面的表格则是使用相同的组件来随机地选取大量数据的结果:
随机选取数据
UnPrepared 11.514
Prepare 11.496
Stored Procedure10.866
从这个结果中我们可以看到,UnPrepared的TADOQuery仍然无法和Prepared
的TADOQuery以及TADOStroredProc相比。而在处理大量数据的情形下,直接使
用存储过程的执行效率的优势也就更明显了。
许多人喜欢使用TADOStoredProc组件来增加应用程序的执行效率,因为
TADOStoredProc组件会调用数据库的存储过程来执行工作。在处理大量数据的情
形下,TADOStoredProc可以增加应用程序的执行效率,但它的缺点就是应用程序
会和特定的数据库绑在一起。我个人比较喜欢使用PreparedTADODataSet或
TADOQuery来执行应用程序,因为我经常会使用不同的数据库,因此我并不想和
任何特定的数据库绑在一起。你可以根据你的需要来选择适当的ADOExpress组件
来使用。

test:

declare @P1  int
exec sp_prepare @P1 output, N'@orderid bigint',
 N'SELECT top 100 * from liebo.orderflow.[order] with(nolock)
 where orderid=@orderid
  ', 1
select @P1
exec sp_execute @P1, '110826001488'
exec sp_execute @P1, '110826002278'
exec sp_execute @P1, '110826004999'
exec sp_execute @P1, '110826006893'

 

 

 

 

 

 

 

 

 

 

 

 

===================================

 

[分享]sp_prepare你用过吗?
最近研究ADO的数据构形技术的时候,跟踪SQL Server发现有如下的SQL代码被执行

SET NO_BROWSETABLE OFF — 这个未公开的设置,不知道是什么作用
SET FMTONLY ON select bill_id from tbl_wh_bill_detail SET FMTONLY OFF
SET NO_BROWSETABLE ON

declare @P1 int
set @P1=22
– 我要说的就是这个 sp_prepare ,用来预编译SQL语句
exec sp_prepare @P1 output, N’@P1 uniqueidentifier’, N’SELECT * FROM tbl_wh_bill_detail where bill_id = @P1′, 1
select @P1

SET NO_BROWSETABLE OFF
SELECT * FROM tbl_wh_bill_head where warehouse = ‘2002′
SET NO_BROWSETABLE ON

– 这是我第一次见到 sp_execute 的这种用法,用她来执行预编译SQL语句,比反复调用sp_executesql效率高多了
exec sp_execute 22, ‘9E44402B-12CF-4AB4-B1A7-00AB21608CDB’
exec sp_execute 22, ‘44811ABA-5B1E-4CE2-8E67-0744FCEDB072′
exec sp_execute 22, ‘BFBAF066-4A28-42E0-9A90-08912DF18E13′
exec sp_execute 22, ‘16572595-B555-4D8E-96DF-0A48350820A6′
exec sp_execute 22, ‘FADD71DA-9381-4207-8266-0D0F0FFECCC0′

/*
–如果用sp_executesql,每一次调用都必须重新编译, 形如:
exec sp_executesql N’SELECT * FROM tbl_wh_bill_detail where bill_id = @P1′
,N’@P1 uniqueidentifier’
,’9E44402B-12CF-4AB4-B1A7-00AB21608CDB’

*/

以下是ADO的数据构形技术相关的VBA代码:

Private Sub Command25_Click()
Dim rst As New ADODB.Recordset
Dim rs As New ADODB.Recordset

‘这种用法是非参数话的构形,效率比以下这种方式低
‘rst.Open "SHAPE {SELECT * FROM tbl_wh_bill_head where warehouse = ‘2002′} " _
‘ & " APPEND ({SELECT * FROM tbl_wh_bill_detail} AS BillDetail " _
‘ & " RELATE bill_id TO PARAMETER 0)" _
‘ , CurrentProject.Connection

‘这里用参数话的构形,
rst.Open "SHAPE {SELECT * FROM tbl_wh_bill_head where warehouse = ‘2002′} " _
& " APPEND ({SELECT * FROM tbl_wh_bill_detail where bill_id = ?} AS BillDetail " _
& " RELATE bill_id TO PARAMETER 0)" _
, CurrentProject.Connection

Set rs = rst("billdetail").Value

Do Until rst.EOF
Debug.Print rs("bill_id"), rst("bill_code")

Do Until rs.EOF
Debug.Print rs("bill_id"), rs("item_name")
rs.MoveNext
Loop

rst.MoveNext ‘rst 移动记录指针的时候, rs是只是相应的记录, 如果是用参数话的构形,每次只从服务器返回相应的记录,而不是一次性返回所有
Loop

rs.Close
rst.Close
Set rst = Nothing
Set rs = Nothing

End Sub

为了说明问题,再转贴一篇

来自:t1122, 时间:2002-1-21 22:13:00, ID:875327

以下是李维的书上的测试:
是测试UnPrepared的TADOQuery组件、Prepared的TADOQuery组件以
及TADOStoredProc组件执行新增数据的范例应用程序的执行画面。由于这个范例
应用程序使用了相同的方式新增大量的数据,因此我们可以通过它来测试
UnPrepared的TADOQuery组件、Prepared的TADOQuery组件以及TADOStoredProc
组件相对的执行效率。
执行这个范例应用程序时,也激活了MSSQLProfiler来观察这三个不同的组
件在同样新增数据时执行的行为是什么?下面的数据是UnPrepared的TADOQuery
组件执行新增数据时MS SQL Profiler 观察到的Action Query :
sp_executesql N’insert into ADOTestDatas
(ID, Name, Phone, Address, Salary, EDate)
values
(@P1, @P2, @P3, @P4, @P5, @P6)
‘, N’@P1 varchar(10),@P2 varchar(10),@P3 varchar(13),@P4
varchar(50),@P5 float,@P6 datetime’, ‘K334646237′, ‘dbuuaiudlo’,
‘5388648427081′,
‘icwwoapxxxabukwhbciietruytkpftlgnpqqsclcsprmnhpkxu’ ,
99572.479999999996, ‘20000625 15:27:19:000′
. . .
当应用程序使用UnPrepared的TADOQuery组件新增数据时,对于每一笔新增
的数据,ADO驱动程序都会执行一次上面的SQL命令。从这个观察的结果我们可
以看到,在使用UnPrepared的TADOQuery组件时,MSSQLServer会将每一笔新增
数据的ActionQuery编译成一个暂时的存储过程,再执行它。因此,如果新增了
1000笔数据,那么Action Query 便被编译了1000次。
下面的数据则是当Prepared的TADOQuery组件执行时MS SQL Profiler 观察到
的结果。可以看到,当使用Prepared的TADO Query组件时,MSSQL Server 只会先
编译Action Query 一次成为一个暂时的存储过程:
declare @P1 int
set @P1=NULL
exec sp_prepare @P1 output, N’@P1 varchar(10),@P2 varchar(10),@P3
varchar(13),@P4 varchar(50),@P5 float,@P6 datetime’, N’insert into
ADOTestDatas
(ID, Name, Phone, Address, Salary, EDate)
values
(@P1, @P2, @P3, @P4, @P5, @P6)
‘, 1
select @P1
而当Prepared的TADOQuery组件新增每一笔数据时,MSSQL Server 只是执行
刚才编译的暂时存储过程,并且只把参数传递给这个暂时的存储过程:
sp_execute 1, ‘Z252651567′, ‘yexoxpwyck’, ‘6683134408672′,
‘ozerprmgkijeypizrftswouqbmekuxlasrgubzmciwqtuqmjvx’ ,
13449.690000000001, ‘20000625 15:27:36:000′
至于范例应用程序使用TADOStoredProc组件执行新增数据时,它的Action
Query和使用Prepared的TADOQuery组件几乎是一样的。只是TADOStoredProc组件
连第一次编译暂时存储过程的步骤也不用,因为TADOStoredProc组件已经连接了
一个已经存在的存储过程,因此只需要传递参数给这个已经存在的存储过程执行
新增数据的工作即可。
从上面的讨论之中你可以了解,对于应用程序中经常执行的SQL命令而言,使
用Prepared的TADOQuery会比使用UnPrepared的TADOQuery来得快速,因为
Prepared的TADOQuery可以省去每次都需要数据源编译SQL命令的步骤。而Prepared
的TADOQuery和TADOStoredProc的执行效率应该差不多,TADOStoredProc会比
Prepared的TADOQuery来得快一点。
下面的表格便是这三种组件在执行新增数据时的结果:
新增数据(1000笔)新增数据(5000笔)
UnPrepared4.46628
Prepare3.58526.117
Stored Procedure 3.82528.561
上面的执行结果也证明了UnPrepared的TADOquery的执行效率比Prepared的
TADOQuery和TADOStoredProc低一些。
下面的表格则是使用相同的组件来随机地选取大量数据的结果:
随机选取数据
UnPrepared 11.514
Prepare 11.496
Stored Procedure10.866
从这个结果中我们可以看到,UnPrepared的TADOQuery仍然无法和Prepared
的TADOQuery以及TADOStroredProc相比。而在处理大量数据的情形下,直接使
用存储过程的执行效率的优势也就更明显了。
许多人喜欢使用TADOStoredProc组件来增加应用程序的执行效率,因为
TADOStoredProc组件会调用数据库的存储过程来执行工作。在处理大量数据的情
形下,TADOStoredProc可以增加应用程序的执行效率,但它的缺点就是应用程序
会和特定的数据库绑在一起。我个人比较喜欢使用PreparedTADODataSet或
TADOQuery来执行应用程序,因为我经常会使用不同的数据库,因此我并不想和
任何特定的数据库绑在一起。你可以根据你的需要来选择适当的ADOExpress组件
来使用。

 

这篇关于sp_prepare与语句句柄的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/874976

相关文章

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

MySQL 中的 LIMIT 语句及基本用法

《MySQL中的LIMIT语句及基本用法》LIMIT语句用于限制查询返回的行数,常用于分页查询或取部分数据,提高查询效率,:本文主要介绍MySQL中的LIMIT语句,需要的朋友可以参考下... 目录mysql 中的 LIMIT 语句1. LIMIT 语法2. LIMIT 基本用法(1) 获取前 N 行数据(

MySQL中动态生成SQL语句去掉所有字段的空格的操作方法

《MySQL中动态生成SQL语句去掉所有字段的空格的操作方法》在数据库管理过程中,我们常常会遇到需要对表中字段进行清洗和整理的情况,本文将详细介绍如何在MySQL中动态生成SQL语句来去掉所有字段的空... 目录在mysql中动态生成SQL语句去掉所有字段的空格准备工作原理分析动态生成SQL语句在MySQL

Go 语言中的select语句详解及工作原理

《Go语言中的select语句详解及工作原理》在Go语言中,select语句是用于处理多个通道(channel)操作的一种控制结构,它类似于switch语句,本文给大家介绍Go语言中的select语... 目录Go 语言中的 select 是做什么的基本功能语法工作原理示例示例 1:监听多个通道示例 2:带

mysql的基础语句和外键查询及其语句详解(推荐)

《mysql的基础语句和外键查询及其语句详解(推荐)》:本文主要介绍mysql的基础语句和外键查询及其语句详解(推荐),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录一、mysql 基础语句1. 数据库操作 创建数据库2. 表操作 创建表3. CRUD 操作二、外键

MySQL INSERT语句实现当记录不存在时插入的几种方法

《MySQLINSERT语句实现当记录不存在时插入的几种方法》MySQL的INSERT语句是用于向数据库表中插入新记录的关键命令,下面:本文主要介绍MySQLINSERT语句实现当记录不存在时... 目录使用 INSERT IGNORE使用 ON DUPLICATE KEY UPDATE使用 REPLACE

python之流程控制语句match-case详解

《python之流程控制语句match-case详解》:本文主要介绍python之流程控制语句match-case使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录match-case 语法详解与实战一、基础值匹配(类似 switch-case)二、数据结构解构匹

grom设置全局日志实现执行并打印sql语句

《grom设置全局日志实现执行并打印sql语句》本文主要介绍了grom设置全局日志实现执行并打印sql语句,包括设置日志级别、实现自定义Logger接口以及如何使用GORM的默认logger,通过这些... 目录gorm中的自定义日志gorm中日志的其他操作日志级别Debug自定义 Loggergorm中的

在MySQL执行UPDATE语句时遇到的错误1175的解决方案

《在MySQL执行UPDATE语句时遇到的错误1175的解决方案》MySQL安全更新模式(SafeUpdateMode)限制了UPDATE和DELETE操作,要求使用WHERE子句时必须基于主键或索引... mysql 中遇到的 Error Code: 1175 是由于启用了 安全更新模式(Safe Upd

封装MySQL操作时Where条件语句的组织

在对数据库进行封装的过程中,条件语句应该是相对难以处理的,毕竟条件语句太过于多样性。 条件语句大致分为以下几种: 1、单一条件,比如:where id = 1; 2、多个条件,相互间关系统一。比如:where id > 10 and age > 20 and score < 60; 3、多个条件,相互间关系不统一。比如:where (id > 10 OR age > 20) AND sco