对于参数化查询,使用显式SQL语句与sp_executesql
之间是否存在性能(或任何其他)差异?
E.g。 SQL语句:
DECLARE @objectName SYSNAME, @objectType CHAR(2)
SELECT @objectName = N'sysrscols', @objectType='s'
SELECT *
FROM sys.objects
WHERE [name] = @objectName AND [type] = @objectType
同样通过sp_executesql
:
EXEC sys.sp_executesql
N'select * from sys.objects where [name] = @objectName and [type] = @objectType',
N'@objectName SYSNAME, @objectType CHAR(2)',
@objectName = N'sysrscols', @objectType = 's'
为什么实体框架使用sp_executesql
?使用SQL Server Profiler查看它生成的查询时,如果它们只是SQL语句,则读取它们会容易得多。
答案 0 :(得分:2)
区别在于,如果只有参数发生变化,SQL服务器将如何优化执行。如果使用这样的普通语句,则每次运行时都将按原样编译和执行语句。如果您使用sp_executesql
并仅使用其他参数运行许多次,SQL服务器“很可能”重用执行计划,从而节省了性能:
可以使用sp_executesql代替存储过程来执行 当参数值发生变化时,Transact-SQL语句多次出现 声明是唯一的变化。因为Transact-SQL 语句本身保持不变,只有参数值 更改后,SQL Server查询优化器很可能会重用 它为第一次执行生成的执行计划。
答案 1 :(得分:2)
细微差别是第一个查询未参数化。它是一批SQL语句,其中在查询中使用局部变量。这批语句作为批处理请求发送到SQL Server,没有参数,在编译和执行时。您可以从跟踪(Profiler或扩展事件)中看到事件类型为*batch*
而不是*rpc*
。
当SqlClient应用程序(包括EF生成的SQL语句)使用参数化查询时(通过在SQL语句中向SqlCommand.Parameters
集合和参数名称添加参数),请求作为RPC发送到SQL Server(远程过程调用) )请求定义参数值的位置,并与SQL语句本身分开传递。跟踪事件将显示rpc_*
而不是sql_batch_*
。 SqlClient API为此使用了sp_executesql。
参数化查询有许多好处,无论是由EF生成还是直接在代码中生成。其中包括:
我将补充说,您在RPC调用的Profiler跟踪中看到的文本只是对底层TDS协议请求的逆向工程。如果您运行网络跟踪,则不会看到您在跟踪中看到的sp_executesql
语句的引用。但参数化查询的要点是参数值以原生格式单独传递给SQL Server。