在 sp_executesql 中使用 @ParmDefinition 有什么好处
What is the advantage of using @ParmDefinition in sp_executesql
DECLARE @id int
DECLARE @name nvarchar(20)
SET @id = 5
SET @name = 'Paul'
这两个选项有什么区别:
Set @SQLQueryInnen = 'SELECT * FROM someTable WHERE ID = ' + @id + ' AND NAME = ''' + @name + ''''
Execute sp_Executesql @SQLQueryInnen
和
Set @SQLQueryInnen = 'SELECT * FROM someTable WHERE ID = @id AND NAME = @name'
Set @ParmDefinition = '@id int, @name nvarchar(20)'
Execute sp_Executesql @SQLQueryInnen, @ParmDefinition, @id
到目前为止,我只看到在使用@ParmDefinition 时两次声明@id 和@name 的数据类型的开销。另一方面,"string-building" 使用@ParamDefinition 似乎更容易一些。
您避免使用 字符串 类型的代码 - 您必须将所有内容转换为字符串,以便您可以将其推入 @SQLQueryInnen
参数,然后引入问题,因为您必须弄清楚如何安全、明确地将字符串转换回正确的原始数据类型。
对于 int
s,转换问题不是很明显。但是,如果您查看人们报告的问题数量(此处和其他论坛),他们在 datetime
和字符串之间转换时遇到问题,您就会意识到这确实会导致真正的问题。最好始终保持数据的自然类型。
第一种情况 SQL 容易注入并且存在安全风险。讨论到此为止。
我看到没有人提到最重要的事情之一。当您使用参数化查询时,您的执行计划会被缓存。
您的查询是:
SELECT *
FROM someTable
WHERE ID = @id
AND NAME = @name;
它的执行计划将存储在内存中,每次查询时都会重复使用(这是一个很大的好处)。同时,如果您使用这样的字符串连接生成代码:
Set @SQLQueryInnen = 'SELECT * FROM someTable WHERE ID = ' + @id + ' AND NAME = ''' + @name + ''''
Execute sp_Executesql @SQLQueryInnen
您的代码将为每个参数组合生成执行计划(除非重复)并且不会重复使用缓存的计划。假设您要传递 @Id = 1
和 @Name = 'Paul'
,您生成的查询将如下所示:
SELECT *
FROM someTable
WHERE ID = 5
AND NAME = 'Paul';
如果您将名称更改为 'Rob'
,您生成的查询将看起来像 SQL 服务器必须为其创建一个新计划:
SELECT *
FROM someTable
WHERE ID = 5
AND NAME = 'Rob';
意思是计划不会被重复使用。希望对你有帮助。
这篇文章对此进行了更详细的解释:EXEC vs. sp_executeSQL(不要依赖文章标题,它解释了您在问题中提出的确切差异)。引用自:
The TSQL string is built only one time, after that every time same
query is called with sp_executesql, SQL Server retrieves the query
plan from cache and reuses it
DECLARE @id int
DECLARE @name nvarchar(20)
SET @id = 5
SET @name = 'Paul'
这两个选项有什么区别:
Set @SQLQueryInnen = 'SELECT * FROM someTable WHERE ID = ' + @id + ' AND NAME = ''' + @name + ''''
Execute sp_Executesql @SQLQueryInnen
和
Set @SQLQueryInnen = 'SELECT * FROM someTable WHERE ID = @id AND NAME = @name'
Set @ParmDefinition = '@id int, @name nvarchar(20)'
Execute sp_Executesql @SQLQueryInnen, @ParmDefinition, @id
到目前为止,我只看到在使用@ParmDefinition 时两次声明@id 和@name 的数据类型的开销。另一方面,"string-building" 使用@ParamDefinition 似乎更容易一些。
您避免使用 字符串 类型的代码 - 您必须将所有内容转换为字符串,以便您可以将其推入 @SQLQueryInnen
参数,然后引入问题,因为您必须弄清楚如何安全、明确地将字符串转换回正确的原始数据类型。
对于 int
s,转换问题不是很明显。但是,如果您查看人们报告的问题数量(此处和其他论坛),他们在 datetime
和字符串之间转换时遇到问题,您就会意识到这确实会导致真正的问题。最好始终保持数据的自然类型。
第一种情况 SQL 容易注入并且存在安全风险。讨论到此为止。
我看到没有人提到最重要的事情之一。当您使用参数化查询时,您的执行计划会被缓存。
您的查询是:
SELECT *
FROM someTable
WHERE ID = @id
AND NAME = @name;
它的执行计划将存储在内存中,每次查询时都会重复使用(这是一个很大的好处)。同时,如果您使用这样的字符串连接生成代码:
Set @SQLQueryInnen = 'SELECT * FROM someTable WHERE ID = ' + @id + ' AND NAME = ''' + @name + ''''
Execute sp_Executesql @SQLQueryInnen
您的代码将为每个参数组合生成执行计划(除非重复)并且不会重复使用缓存的计划。假设您要传递 @Id = 1
和 @Name = 'Paul'
,您生成的查询将如下所示:
SELECT *
FROM someTable
WHERE ID = 5
AND NAME = 'Paul';
如果您将名称更改为 'Rob'
,您生成的查询将看起来像 SQL 服务器必须为其创建一个新计划:
SELECT *
FROM someTable
WHERE ID = 5
AND NAME = 'Rob';
意思是计划不会被重复使用。希望对你有帮助。
这篇文章对此进行了更详细的解释:EXEC vs. sp_executeSQL(不要依赖文章标题,它解释了您在问题中提出的确切差异)。引用自:
The TSQL string is built only one time, after that every time same query is called with sp_executesql, SQL Server retrieves the query plan from cache and reuses it