在 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 参数,然后引入问题,因为您必须弄清楚如何安全、明确地将字符串转换回正确的原始数据类型。

对于 ints,转换问题不是很明显。但是,如果您查看人们报告的问题数量(此处和其他论坛),他们在 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