在存储过程中,最好是简单地查询数据或构造查询然后执行它?为什么?

时间:2010-10-29 15:45:22

标签: sql sql-server stored-procedures

我已经研究过SQL存储过程,我注意到很多人使用两种不同的方法 -

首先,使用选择查询,例如

Select * from TableA where colA = 10 order by colA

其次,是通过构建一个查询来做同样的事情,比如

Declare @sqlstring varchar(100)
Declare @sqlwhereclause varchar(100)
Declare @sqlorderby varchar(100)

Set @sqlstring = 'Select * from TableA '
Set @sqlwhereclause = 'where colA = 10 '
Set @sqlorderby = 'order by colA'

Set @sqlstring = @sqlstring + @sqlwhereclause + @sqlorderby 
exec @sqlstring

现在,我知道两者都很好。但是,我提到的第二种方法是维护有点烦人。

我想知道哪一个更好?是否有任何具体原因可以采用一种方法而不是另一种方法?一种方法比其他方法有什么好处?

4 个答案:

答案 0 :(得分:5)

使用第一个。这将允许正确缓存查询计划,除了您应该使用SQL的方式。

除了其他问题之外,第二个对SQL注入攻击持开放态度。

使用动态SQL,您将无法进行编译时检查,因此只有在调用时才会失败(您越早了解错误的语法,就越好)。

并且,您注意到自己,维护负担也更高。

答案 1 :(得分:4)

第二种方法的明显缺点是在编译时没有检查语法。但它确实允许动态order by子句,而第一个不允许。我建议您始终使用第一个示例,除非您有充分的理由使查询动态化。并且,正如@Oded已经指出的那样,如果你采用第二种方法,一定要保护自己免受sql注入。

答案 2 :(得分:1)

我没有完整的全面答案,但我现在可以告诉你,当将存储过程作为ORM中的函数导入时,后一种方法更难处理。由于SQL是动态构造的,因此您必须手动创建从存储过程返回的与模型中的实体不直接相关的任何类型类。

考虑到这一点,有时候你根本无法避免构造一个SQL语句,特别是当where子句和连接取决于传入的参数时。根据我的经验,我发现存储的procs正在创建大对于EXEC来说,可变联合/轮换语句试图做太多事情。在这些情况下,我建议您记住单一责任原则。

答案 3 :(得分:1)

在存储过程中执行动态SQL会将使用存储过程的值降低为仅保存的查询容器。存储过程大多是有益的,因为查询执行计划(非常昂贵的操作)在第一次执行过程时被编译并存储在存储器中。这意味着程序的每个后续执行都绕过查询计划计算,并直接跳转到操作的数据检索端口。

此外,允许存储过程将可执行查询字符串作为参数是危险的。对程序授予执行权限的任何人都可能对数据库的其余部分造成严重破坏。