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); 
相关推荐
aloha_7892 天前
Java 基础、集合、异常与 JUnit 5 速查
java·junit·sqlserver
betazhou6 天前
Apache Seatunnel 抽取SQL server实时同步到Oracle-多表同步(五)
数据库·oracle·sqlserver·apache·seatunnel
betazhou8 天前
Apache seatunel配置-数据同步测试(直接把采集数据打印到控制面板) - SQL server
sqlserver·apache·seatunnel
福娃筱欢10 天前
SQLServer迁移至KES SQLServer模式 问题整理
数据库·oracle·sqlserver
xuefuhe16 天前
SQL Server:数据库没配置publication,但sp_replcounters 显示有事务积压
sqlserver
geovindu23 天前
sql: JSON and XML Data Handling in SQL using sql server 2025
大数据·数据库·sqlserver·数据库开发·数据库架构
路远的数据库笔记23 天前
SQL Server迁移国产数据库怎么做?九套口岸库零停机割接实战
数据库·经验分享·sqlserver·dba
xuefuhe25 天前
SQL Server AG从节点关机-Replication异常-TF1448
sqlserver
Arcai102425 天前
SQL Server 备份和恢复完全指南:从入门到精通
数据库·sqlserver·数据恢复·数据备份·备份一体机·杭州智备
xuefuhe1 个月前
SQL Server:replication添加新的article而无需对旧的重新生成snapshot
sqlserver