使用SqlServer Views有哪些缺点?

25

使用SqlServer视图的缺点是什么?

我经常创建视图以以去规范化的形式显示我的数据。

相较于在许多表之间生成复杂的联接查询,我发现使用其中一个联接查询要简单得多,因此更快、不易出错、更具自文档化性质。尤其是当我从不同角度分析相同的数据(许多相同字段、相同表联接)时。

但是,创建和使用这些视图是否有成本?

我会减慢(或加速?)查询处理吗?


1
在我的经验中,关于数据库视图存在着大量的无知和错误信息。也许有很多关于视图的讨论,但我不确定它们是否被框定在这样的范畴内,答案是否显而易见。 - Paul Sasik
23
我认为人们在这里提问,即使答案很容易通过谷歌搜索得到,也是因为他们想要 Stack Overflow 提供的互动性和后续的追问/问答环节,我不认为我们应该打击这种行为。 - JNK
@Lill,不幸的是,我认为没有一个简单的答案 :( - Mr Shoubs
@Paul,同意 - 它们很容易被滥用。测试和比较。 - Mr Shoubs
它们特别适合重复使用。 - Mr Shoubs
显示剩余4条评论
10个回答

20

在涉及到视图时,有优点和缺点。

优点:

  1. 它们是虚拟表而不是作为单独对象存储在数据库中。所有存储的只是SELECT语句。
  2. 通过限制用户可以看到什么来使用它作为安全措施。
  3. 它可以通过将复杂的常用查询封装成视图来使其更易于阅读。这是一个双刃剑 - 参见缺点#3。

缺点:

  1. 它没有优化的执行计划缓存,因此速度不如存储过程快。
  2. 由于它基本上只是SELECT的抽象,所以比纯SELECT稍微慢一些。
  3. 它可能会隐藏复杂性并导致意外情况。(意外情况:ORDER BY未被识别)。

我个人的观点是不要使用视图,而应改用存储过程,因为它们提供了视图的安全性和封装性,同时也带来了更好的性能。


4
我认为最大的危险来自于第三个劣势。隐藏的复杂性可能是危险的。通常使用视图的目的是“简化”,但长期来看可能会导致更多问题。 - GrowlingDog
3
您能否解释一下“ORDER BY未被尊重”的问题以及它的表现形式。如果您愿意回答,我还有一个问题。https://dev59.com/D1bUa4cB1Zd3GeqPC-QM - Toby Allen

12
使用视图的一个可能的缺点是,您会抽象出底层设计的复杂性,这可能会导致初级开发人员和报告创建者滥用它们。 对于一个特别大且复杂的项目,我设计了一组视图,主要由报告设计人员使用来填充水晶报表。几周后我发现,初级开发人员开始使用这些视图来获取聚合并连接已经很大的视图,只是因为它们存在并且易于消费。(数据库中有强烈的EAV设计元素)。我后来得知这件事后,才知道初级开发人员开始询问为什么看似简单的报告需要执行多分钟。

7
视图的效率在很大程度上取决于底层表。视图实际上只是一种有组织且一致的查看查询结果的方式。如果用于形成视图的查询良好,并且在底层表上使用适当的索引,则视图不应对性能产生负面影响。
在SQL Server中,您还可以创建材料化或索引视图(自SQL Server 2000以来),这会稍微提高速度。

2
一如既往,未注明来源和未加注释的踩是受欢迎的 :P - JNK

4

当视图包含未被最终查询使用的逻辑、列、行或表格时,视图可能会对性能产生负面影响。我不能告诉你有多少次我看到过这样的情况:

SELECT ... 
FROM (View with complex UNION of ActiveCustomer and InactiveCustomer tables)
WHERE Active = True 

因此,过滤掉从InactiveCustomer表中包含在视图中的所有行,或者。
SELECT (one column)
FROM (view that returns 50 columns)

SQL需要检索许多数据,然后在稍后的步骤中将其丢弃。可能那些其他列的检索成本很高,例如通过书签查找。

SELECT ...
FROM (view with complex filters)
WHERE (entirely different filters)

如果直接查询表格,很可能SQL可以使用更合适的索引,

或者
SELECT (only fields from a single table)
FROM (view that contains crazy complex joins)

有很多CPU开销通过连接产生,以及为后来被丢弃的表读取而进行的不必要IO操作,或者是我最喜欢的:

SELECT ...
FROM (Crazy UNION of 12 tables each containing a month of data)
WHERE OrderDate = @OrderDate

(只需读取1个表格,却读取了12个表格。)在大多数情况下,SQL足够聪明,能够“看穿”表面并提供有效的查询计划。但在某些情况下(尤其是非常复杂的情况下),它无法做到这一点。在上述每种情况下,答案是删除视图,而是查询底层表格。至少(即使您认为SQL会聪明地进行优化),消除视图有时也可以使您自己的查询调试和优化更加容易(更加明显需要做什么)。

不确定问题出在哪里:SELECT ... FROM(具有活动和非活动客户疯狂联合的视图)WHERE Active = True。您是说应该再添加两个视图,一个包含所有活动客户,另一个包含非活动客户。因此,如果您只需要活动客户,则查询“活动”视图等? - Lill Lansey
@Lill 好的,在这个(人为制造的)例子中,视图结合了来自表格的数据,然后被最终查询过滤掉。因此,直接查询ActiveCustomer表格,完全绕过视图。 - BradC
1
关于 SELECT (一个列) FROM (有50个列的视图) - 在 SQL Server 2008 上查看执行计划,实际上已经被优化掉了。对于 SELECT (来自单个表的字段) FROM (具有疯狂复杂连接的视图) 也是一样的 - 执行计划会删除不需要的连接以提高查询效率。 - daiscog

4

我也经常使用视图。然而需要注意的一点是,如果基础表经常更改(特别是在开发期间),使用大量视图可能难以维护。

编辑:话虽如此,我发现能够简化和重复使用复杂查询的方便性和优势超过了维护问题,尤其是如果视图被负责任地使用的话。


3
我遇到的一个视图的缺点是,在将它们合并到分布式查询中时,性能会下降。这篇SQLMag文章讨论了这个问题,虽然在演示中我使用了高度人工化的数据,但在“现实世界”中,我一次又一次地遇到了这个问题。
尊重你的视图,它们也会好好对待你。

3

SQL Server中视图的各种限制是什么?

视图的前11个限制

  • 视图不支持COUNT();但它可以支持COUNT_BIG(
  • ORDER BY子句在视图中不起作用
  • 当我们需要另一列时,常规查询或存储过程为我们提供了灵活性;我们可以立即向常规查询添加列。如果我们想要在视图中执行相同的操作,则必须首先修改它们
  • 在视图上创建的索引不经常使用
  • 一旦创建了视图,并且如果基本表添加或删除了任何列,则通常不会在视图中反映出来,直到刷新为止
  • 不允许在索引视图中进行UNION操作
  • 我们不能在嵌套视图情况下创建索引,这意味着我们不能在从另一个视图构建的视图上创建索引。
  • 不允许在索引视图中进行自连接
  • 不允许在索引视图中进行外连接
  • 不允许在索引视图中进行跨数据库查询

来源:SQL MVP Pinal Dave

http://blog.sqlauthority.com/2010/10/03/sql-server-the-limitations-of-the-views-eleven-and-more/


1

当我开始时,我总是认为视图会增加性能开销,但是经验告诉我们不同的故事(视图机制本身的开销可以忽略不计)。

这完全取决于底层查询是什么。查看索引视图此处此处,最终您应该测试两种方法的性能,以获得清晰的性能概要。


好的,好的,谈论被跳过 - 我听起来比预期的要糟糕得多。 - Mr Shoubs
@Mr Shoubs。也许有很多信息,但也可能是太多了。我不想花三天时间浏览数百页的文档。我只想要一个简单的答案。我想我本可以只问一个好链接,给我一个问题的答案。然后依靠得票最多的那些答案。 - Lill Lansey

0

我最大的不满是在视图中无法使用ORDER BY。虽然这很有道理,但如果没有预料到它可能会出现问题。因此,在一些情况下,为了不能在稍后指定ORDER BY,我不得不从使用视图转向使用SPROCS(它们本身就有足够多的问题)。(我希望有一个带有“FINAL VIEW”结构的构造——例如,可能包括order by——语义)。

http://blog.sqlauthority.com/2010/10/03/sql-server-the-limitations-of-the-views-eleven-and-more/ (限制#1是关于ORDER BY的:-)


-2
以下是一种 SQL 黑科技,允许在视图中引用 order by:
create view toto1 as 
select top 99.9999 percent F1
from Db1.dbo.T1 as a 
order by 1

但是我的偏好是使用Row_Number

create view toto2 as 
select *,  ROW_NUMBER() over (order by [F1]) as RowN from ( 
select f1
from Db1.dbo.T1) as a

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接