sql server-存储过程是否真正提高了MS sql/.NET的性能



Jeff Atwood在这里写到了这一点,虽然我理解存储过程可以提供的理论性能提升,但这似乎是一个巨大的痛苦。

使用存储过程,您会看到哪些类型的查询的性能提高最大,而您更愿意动态构建什么类型的查询?

任何以某种方式提供的文件都将不胜感激。

存储进程/无存储进程的争论已经成为一个宗教问题。对于每一个强调优化proc执行计划的人,另一个人指出,在大多数现代DBMS中,常见的动态查询都是缓存和优化的。对于任何指出proc可能提供的安全性的人来说,另一位解释说,动态查询也可以同样安全。一些人喜欢在不重新编译应用程序的情况下更改proc的灵活性,而另一些人则认为查询应该在应用程序代码中捕获,这样它们就可以在同一代码库中生存和增长。

我说。。。

做你喜欢的事。我怀疑我们能否想出正确的答案。如果proc很麻烦,就不要使用它们。如果它们看起来是个好主意,那就去做吧。我和这两个模特都合作过,老实说,我没有偏好。不管有没有他们,我都很有效率。

在过去的日子里,使用存储过程带来了可观的性能优势,但查询计划重用现在明显更好了,因此在许多情况下两者几乎相同。

如果在服务器上构建动态SQL,则可以使用sp_ExecuteSQL(而不仅仅是EXEC)来执行SQL,从而进一步提高查询计划的重用性(和注入安全性)。

使用存储过程有一些优点:

  • 他们准确地修复了数据库中会发生的事情
  • 对于严格的安全场景,可以严格控制对存储过程(而不是表)的访问
  • 如果计划在某些地方变得异常(嗅探),您可以细分查询

然而,SQL也有优点:

  • 它允许ORM工具(例如LINQ)动态编写可组合查询(第4页,由Foo、Bar排序)
  • 它允许您用更具表现力的语言编写动态代码(TSQL并不是真正用来编写TSQL的!)
  • 你通常有更好的工具

我肯定会在(例如)数据迁移步骤中使用SP,即对于大容量操作,我可能会使用SqlBulkCopy将数据推送到暂存表中,然后使用存储过程将数据移动。除此之外,我相当灵活。

正如软件中常见的那样,SQL缓存问题比看起来更微妙。例如,让我们来看看ad-hoc SQL查询的缓存:

-- First, clear the cache
DBCC FREEPROCCACHE
-- Look at what executable plans are in cache
SELECT sc.*
FROM master.dbo.syscacheobjects AS sc
WHERE sc.cacheobjtype = 'Executable Plan'
-- Execute the following statement
SELECT t.*
FROM pubs.dbo.titles AS t
WHERE t.price = 19.99
-- Look at what executable plans are in cache and you'll 
-- find that there's a plan for a NUMERIC(4,2)
SELECT sc.*
FROM master.dbo.syscacheobjects AS sc
WHERE sc.cacheobjtype = 'Executable Plan'
-- If you execute the EXACT same statement with a 4,2 
-- then you will get THAT plan. But if you execute with a 5,2
-- then you'll get a new plan. Try this:
SELECT t.*
FROM pubs.dbo.titles AS t
WHERE price = 199.99
-- Look again at the cached executable plans, and you'll see a NEW one...
SELECT sc.*
FROM master.dbo.syscacheobjects AS sc
WHERE sc.cacheobjtype = 'Executable Plan'

但是,您可以使用sp_executesql键入参数并强制缓存计划。所有后续用途都会得到相同的计划,但有些人不喜欢这种方法的晦涩难懂:

DECLARE @ExecStr nvarchar(4000)
SELECT @ExecStr = N'SELECT t.* FROM dbo.titles AS t WHERE t.price = @price'
EXEC sp_executesql @ExecStr, N'@price money', 19.99

现在,如果您创建了一个类似于存储过程的查询,并带有一个价格参数,那么在第一次执行时,计划将被创建并缓存在内存(而不是磁盘)中,并且无论参数的值如何,都将被重用。

存储过程计划缓存在内存中而不是磁盘上,这意味着它将在服务器重新启动时或由于重用率低而从缓存中掉出来。如果过程所依赖的数据更改到足以导致统计信息无效,则它也可能从缓存中掉出来。这会导致SQL Server使计划无效。

我们发现存储过程的一个好处是,一旦开发人员最初创建了存储过程,它们就可以移交给DBA或数据库调优专家,以便在需要时出于性能原因进行更好的编写。

DBA显然不需要访问应用程序代码就可以做到这一点,并且可以与挂起的应用程序版本一起工作。

诚然,内联或嵌入式SQL查询也是如此,但我认为存储过程更适合这种协作的、更大的团队工作方式。

在我看来,存储过程的最大优势是:

1/他们集中在数据库管理系统中,这样DBA就可以准确地知道他们在做什么,并可以优化数据库以适应他们。对于来自客户端的特殊查询,要做到这一点要困难得多。我看到数据库被收买是因为DBA允许不受约束的查询。他们还强迫客户思考他们需要什么。

2/他们可以在服务器上进行非常复杂的处理,从而最大限度地减少通过网络发送的数据量。这样就避免了应用程序获取一桶数据,从中决定一些内容,然后获取更多数据,等等

无论如何,在开发过程中允许任何随机查询,但在投入生产之前,请确定哪些DB操作应该移动到存储的proc中。

作为一名兼职DBA,我认为这意味着所有这些,但只要你对应用程序可以发送的查询保持一定的控制,就没有必要。

存储过程提供性能优势是SQL Server早期版本遗留下来的神话。SQLServer>version7对所有查询一视同仁,并将缓存所有常用查询的执行计划,无论它们的起源如何。

我想知道这个神话还能流传多少年。

Frans Bouma不久前就因为这个话题引起了轰动。

在SQL Server上,更重要的是要理解任何性能提高都是由于缓存了查询计划。查询计划的编译成本相当高,因此缓存它们是有意义的。编辑:临时SQL不太可能与缓存的查询计划匹配。。如果动态SQL是通过调用sp_executesql运行的,则可以对其进行缓存。

如果使用EXEC运行SQL,例如"EXEC@dynamic_SQL",它将缓存计划,但不会对其进行参数化(或规范化),这意味着除非发送完全相同的查询,否则它不会重用缓存的查询计划。

存储过程背后的一个想法是,它允许您在一次数据库访问中完成几件事。

MSSQL允许在单个请求中提交查询批;这大致相当。

然而,原理是一样的。在大规模分布式系统中,数据库的延迟(而不是查询在服务器上花费的时间)可能是一个性能问题。发出更少的查询可能会有好处。

因此,在分布式系统中,使用查询批处理或存储过程与发出单个查询相比是一种潜在的性能优势。

存储过程之所以更快,是因为它们可以存储缓存的查询计划,有点像预编译存储过程。因此,如果过程非常复杂,在许多表之间有很多联接,那么您可能会看到速度方面的好处。

我认为存储的proc除了速度之外,还有助于抽象数据库模式,并有助于防止sql注入攻击。

写得不好的存储过程不会提高性能。与经过深思熟虑的内联查询相比,糟糕的内联查询的性能更差。

人们跳过的一件事是,所有这些CRUD存储过程都充满了联合语句和if语句,它们的速度非常慢。

如果您使用的是参数化语句,而不是使用存储过程的合并,那么动态语句将获胜。

最新更新