我在这场辩论的两面都读到很多东西:通过仅使用存储过程而不是原始查询,是否可以获得显着的性能提升?我对SQL Server特别感兴趣,但对所有数据库都感兴趣。
我在这场辩论的两面都读到很多东西:通过仅使用存储过程而不是原始查询,是否可以获得显着的性能提升?我对SQL Server特别感兴趣,但对所有数据库都感兴趣。
Answers:
在SQL Server 2008及更高版本中,情况并非如此,但仍然存在。归结为执行计划缓存和SQL Server能够对发送来的查询进行自动参数化。使用存储过程(其中没有动态SQL)时,查询已经被参数化,因此SQL Server不会对参数进行参数化。由于计划已存储在计划缓存中,因此在运行每个查询时,无需为每个查询生成一个计划。
并且不要忘记使用存储过程时会消失的安全性问题(动态SQL,最低权限等)。
当应用程序针对基表使用动态SQL选择,插入,更新和删除表中的数据时,应用程序需要直接拥有对所有这些对象的权限。因此,如果有人使用SQL Injection进入服务器,他们将有权查询,更改或删除这些表中的所有数据。
如果您使用的是存储过程,则他们仅具有执行存储过程的权利,而只获取存储过程将返回的信息。与其发布快速删除语句并将所有内容浪费掉,他们需要找出可以用来删除数据的过程,然后找出如何使用该过程来删除数据。
鉴于SQL注入是闯入数据库的最简单方法,所以这很重要。
作为Denny的答案的补充,找到在单个或少量使用的临时执行计划上浪费大量缓冲池内存的系统并不少见,这是由于在proc上使用查询而创建的。
最近最坏的情况是,为实例分配了8GB,3GB计划缓存,2.5GB一次性使用计划。其中大多数是SQL2005,因此无法尝试针对临时工作负载进行优化设置。
当然,将性能包含在针对原始查询的过程中的理由变得越来越困难。现在对我来说最有力的论据之一是“如果使用过程,当出现性能问题时,对我来说帮助要容易得多”。动态/ linq / orm界面不会阻止您进行调整,但是会严重限制您的选择。
SQL Server以相同的方式缓存和优化存储过程和即席SQL。例如,此过程:
create procedure dbo.TestSB(@id int) as select * from Orders where id = @id
将被优化和缓存为:
select * from Orders where id = @id
但是,由于硬编码值,以下临时SQL无法有效地缓存:
select * from Orders where id = 42
尽管性能相同,但是有充分的理由使用存储过程。存储过程将DBA和应用程序开发人员明确区分。在您的重要数据和不断变化的程序之间增加防御层是一件好事:)
id = 42
可以根据简单/强制参数化设置使用相同的计划优化查询。当然,查询应该适当地参数化。:-)