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 = 1 和 WHERE 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: JSON and XML Data Handling in SQL using sql server 2025
大数据·数据库·sqlserver·数据库开发·数据库架构
路远的数据库笔记2 天前
SQL Server迁移国产数据库怎么做?九套口岸库零停机割接实战
数据库·经验分享·sqlserver·dba
xuefuhe4 天前
SQL Server AG从节点关机-Replication异常-TF1448
sqlserver
Arcai10244 天前
SQL Server 备份和恢复完全指南:从入门到精通
数据库·sqlserver·数据恢复·数据备份·备份一体机·杭州智备
xuefuhe5 天前
SQL Server:replication添加新的article而无需对旧的重新生成snapshot
sqlserver
lusklusklusk6 天前
Sqlserver_Oracle_Mysql_Postgresql表_索引碎片或膨胀的知识点汇总
mysql·oracle·sqlserver
lusklusklusk18 天前
Oracle索引组织表,SQLServer聚集索引,Mysql Innodb表的数据行不是在磁盘上像排队一样严格连续地存放
mysql·postgresql·oracle·sqlserver
geovindu19 天前
sql: Query Design Patterns using sql server 2019
sqlserver·数据库开发·数据库架构
geovindu22 天前
sql: Data Modeling Patterns
数据库·sql·设计模式·sqlserver
1314lay_10071 个月前
C#调用Sql Server存储过程,并且使用传入表结构
数据库·经验分享·笔记·sqlserver·c#