SQL Server exec vs sp_executesql

虽然两者都能执行动态 SQL 字符串,但在安全性、性能和功能上存在本质区别。

通常强烈推荐使用 EXEC sp_executesql

核心区别对比

特性 EXEC sp_executesql EXEC(...)
参数化支持 支持(核心优势) 不支持(只能拼字符串)
SQL 注入风险 极低(通过参数隔离) 极高(容易被恶意拼接)
执行计划重用 高(参数变了,SQL 文本不变) 低(参数变了,每次都要重新编译)
输入/输出参数 支持 OUTPUT 参数返回值 无法直接返回变量值
变量作用域 无法直接访问外部变量 无法直接访问外部变量

关键差异详解

1. 安全性:防御 SQL 注入

  • EXEC(危险):必须把变量拼接到字符串里。如果变量包含恶意代码(如 ' ; DROP TABLE Users; --),会直接被执行。
  • sp_executesql(安全):支持参数化查询。变量值只会被当做"数据"处理,绝对不会当做"代码"执行。

2. 性能:缓存执行计划

  • EXEC:每次传入不同的参数,生成的 SQL 字符串都不同(例如 WHERE ID = 1WHERE ID = 2)。SQL Server 必须每次都重新编译。
  • sp_executesql:SQL 文本保持一致(例如 WHERE ID = @id)。SQL Server 只编译一次,后续传入不同参数时直接重用执行计划,大幅提升性能。

3. 功能:支持 OUTPUT 参数

sp_executesql 可以把动态 SQL 执行的结果赋值回外部变量,而 EXEC 做不到。

  • sp_executesql 示例:

    复制代码
    DECLARE @Count INT;
    -- 可以直接通过 @cnt OUTPUT 把值传出来
    EXEC sp_executesql 
        N'SELECT @cnt = COUNT(*) FROM Users WHERE Status = @status',
        N'@status INT, @cnt INT OUTPUT',
        @status = 1, @cnt = @Count OUTPUT;

唯一例外

当需要动态拼接数据库对象名称(如表名、列名)时,两者都无法使用参数化(因为表名不能作为参数)。此时必须使用字符串拼接,但使用 EXEC 的语法通常更简短:

复制代码
-- 这种情况两者都需要注意防范注入,必须用 QUOTENAME()
DECLARE @TableName NVARCHAR(50) = 'Users';
EXEC('SELECT * FROM ' + @TableName); 
相关推荐
geovindu1 天前
sql: Data Modeling Patterns
数据库·sql·设计模式·sqlserver
1314lay_10075 天前
C#调用Sql Server存储过程,并且使用传入表结构
数据库·经验分享·笔记·sqlserver·c#
1314lay_10075 天前
C#调用Sql Server存储过程,有返回值的
数据库·sqlserver·c#
Aime_Perfect8 天前
sqlserver AlwaysOn(一)
数据库·sqlserver
Aime_Perfect10 天前
sqlserver always on
服务器·数据库·sqlserver
xuefuhe13 天前
SQL Server 模拟checksum检测错误
sqlserver
数智启示录18 天前
Flink CDC 机制精讲(四):一条 SQLServer CDC 事件如何保持顺序 【面试宝典】
数据库·面试·sqlserver·flink
数据库小学妹20 天前
SQL Server数据迁移怎么做?一次事故复盘:备份还原、bcp、CDC、KDTS全拆解
sqlserver·备份还原·数据库迁移·信创迁移·sqlserver数据迁移
zengjuan100521 天前
[特殊字符]️ 松鼠备份 | 数据库备份方案即将重磅上线!三大模式组合拳,精准守护SQL Server每一笔数据
数据库·sqlserver·数据库备份·全量备份·增量备份·差异备份·日志和事务备份