嵌套视图是一种好的数据库设计吗?


42

我很久以前就读过书。本书指出,我们不应允许在SQL Server中具有嵌套视图。我不确定为什么不能这样做,否则我可能会记得错误的陈述。

学生们

SELECT studentID, first_name, last_name, SchoolID, ... FROM students

CREATE VIEW vw_eligible_student
AS 
SELECT * FROM students
WHERE enroll_this_year = 1

教师

SELECT TeacherID, first_name, last_name, SchoolID, ... FROM teachers

CREATE VIEW vw_eligible_teacher
AS 
SELECT * FROM teachers
WHERE HasCert = 1 AND enroll_this_year = 1

学校

CREATE VIEW vw_eligible_school
AS 
SELECT TOP 100 PERCENT SchoolID, school_name 

FROM schools sh 
JOIN
     vw_eligible_student s 
     ON s.SchoolID = sh.SchoolID
JOIN 
     vw_eligible_teacher t
     ON s.SchoolID = t.SchoolID

在我的工作场所,我研究了我们的一个内部数据库应用程序。我检查了发现的对象,发现彼此之间有两三层视图堆栈。所以这让我想起了我过去读过的东西。有人可以帮忙解释一下吗?

如果这样做不合适,我想知道它仅限于SQL Server或通常用于数据库设计。

附加信息:我更新了公司的示例。我进行了一些改动,使其变得更加通用,而没有太多的技术性(此示例中的列太多)。通常,我们使用的嵌套视图基于抽象或聚合视图。例如,我们有一个大学生表,其中有几百列。说,Eligible Student View是根据今年入学的学生而定。符合学生资格的视图可以在其他地方使用,例如在存储过程中。


3
我认为无论平台如何,相同的利弊大致相同。
亚伦·伯特兰

Answers:


47

不论平台如何,以下说明均适用。

(-)嵌套视图:

  • 很难理解和调试

    例如,该视图列指的是哪个表列?Lemme挖掘了 4个级别的视图定义...

  • 使查询优化器更难提出最有效的查询计划

    看到这个这个这个这个作为传闻证据。与进行比较,这表明优化器通常足够聪明,可以正确解压缩嵌套视图并选择最佳计划,但并非没有编译成本。

    您可以通过将视图查询与针对基表编写的等效查询进行比较,来衡量性能成本。

(+)另一方面,嵌套视图使您:

  • 集中和重用聚合或业务规则
  • 抽象您的基础结构(例如,从其他数据库开发人员那里)

我发现它们很少需要。


在您的示例中,您正在使用嵌套视图来集中和重用某些业务定义(例如“什么是合格的学生?”)。这是嵌套视图的有效用法。如果要维护或调整此数据库,请权衡保留它们与删除它们所花费的成本。

  • 保留:通过保留嵌套视图,您会遇到上面列举的优点和缺点。

  • 删除:要删除嵌套视图:

    1. 您需要用其基本查询替换所有出现的视图。

    2. 如果您对符合条件的学生/教师/学校的定义发生了变化,那么您必须记住要更新所有相关的查询,而不是仅仅更新相关的视图定义。


1
+1,除了我用“几乎不可能”将查询优化器的“更难”替换为“几乎不可能”。:)
Jason

1
@Jason-我同意,我希望可以链接到一些具体示例。您是否知道任何解释或证明原因的参考文献?
Nick Chammas

1
我所能找到的只是轶事证据,当使用嵌套视图时,与“扁平化” SQL相比,它们会遇到性能问题。sqlservercentral.com/blogs/2cents/archive/2010/04/05/… 问题似乎归结为以下事实:数据库(在这种情况下为SQL Server)在加入表之前不会应用某些过滤器,因此使查询花费的时间比应该的长。
杰森

7
我不同意查询优化器的问题,因为解决了所有视图后生成的查询将是相同的,无论它经过了多少次视图转换(中间结果集中的一些额外列除外,优化器都可以消除这种情况)。剩下的调试工作;IMO使得嵌套视图的调试变得更加容易,因为我可以查看中间结果以查看出错的地方。
西蒙·里希特

1
我已经编写了一个嵌入式数据库服务器,对我来说,首先解析视图,然后优化结果查询是显而易见的方法,因为对视图的所有查询实际上都不可能返回所有列。我什至想不出为什么在查询中间实现视图数据会有所收获的原因,所以这对我来说很容易。
西蒙·里希特

26

有时,嵌套视图用于防止重复聚合。假设您有一个视图,该视图可以对消息进行计数并按用户标识对消息进行分组,您可以在一个视图上对具有> 100条消息的用户数量进行计数。当基本视图是索引视图时,此方法最有效-您不一定要创建另一个索引视图来代表分组稍有不同的数据,因为现在您要为索引维护支付两次,而性能可能足以对抗原始观点。

如果所有这些都是您正在执行select *但更改顺序或顶部的嵌套视图,则与一堆嵌套视图相比,似乎将其封装为带有参数(或内联表值函数)的存储过程更好。恕我直言。


4
“当基本视图是索引视图时,这最有效。” 很重要的一点。
Nick Chammas

7

更高版本的SQL(2005+)在优化视图使用方面似乎更好。视图最适合用于合并业务规则。EG:我在哪里工作,我们有一个电信产品数据库。每个产品都分配给一个费率计划,该费率计划可以换出,并且随着费率的增加或修改,费率计划中的费率可以被激活/取消激活。

为简单起见,我们可以制作嵌套视图。第一个视图只是使用所需的任何表将费率计划与其费率连接起来,并返回下一级别的视图所需的任何必要数据。第二视图只能隔离活动费率计划及其活动费率。或者,只是客户费率。或员工费率(用于员工折扣)。或企业与住宅客户的费率。(费率计划可能会变得很复杂)。关键是,基础视图可确保我们针对费率计划的整体业务逻辑和费率在一个位置正确地结合在一起。下一层视图使我们更加关注特定的费率计划(类型,活动/不活动等)。

我同意,如果您同时构建查询和视图,则视图会使调试变得混乱。但是,如果您使用的是try-n-trusted视图,它将使调试更加容易。您知道该视图已经通过了振铃器,因此您很可能不会引起问题。

但是,您可能会想到一些问题。“如果产品仅与无效的费率计划相关联,该怎么办?” 或“如果费率计划仅包含无效费率,该怎么办?” 好吧,这可以通过捕获用户错误的逻辑在前端级别捕获。“错误,产品处于无效的价格计划中,请更正”。我们还可以运行查询审计以在开票之前对它进行仔细检查。(选择所有计划并保留加入活动费率计划视图的权限,只返回没有获得活动费率计划的计划作为需要解决的问题)。

这样做的好处是,视图使您可以极大地简化查询以进行报告,计费等。您可以有一个客户帐户视图,然后是活跃客户的第二级视图。将其与客户地址组合在一起。以产品为视角进行团队合作(加入客户拥有的产品)。团队合作以查看产品费率计划。以产品功能为视角进行协作。查看,查看,查看每个审判错误,以确保完整性。使用视图的最终查询非常紧凑。

编辑:

作为一个视图如何比仅对表进行平面查询更好的示例……我们有一个临时承包商来进行一些更改。他们告诉他对事情有看法,但他决定平息所有疑问。Billing摆脱了他的一些疑问。他们不断获得多种利率计划和事物的利率。事实证明,他的查询缺少标准,仅允许费率在费率计划应在其开始和结束日期之间使用该费率时才计费。哎呀。如果他使用了该视图,那么它将已经考虑了该逻辑。

基本上,您必须权衡性能与理智。也许您可以做各种花哨的事情来提高数据库的性能。但是,如果这意味着新人接管/维持职位是一场噩梦,那真的值得吗?真的值得新家伙玩一玩,必须找到所有需要改变其逻辑的查询(并冒着使他忘记/用手指指责的风险)b / c某人认为视图“不好”,难道没有将一些核心业务逻辑整合到可以用于100多个其他查询的逻辑中吗?这实际上取决于您的业务和您的IT / IS / DB团队。但是,与性能相比,我更喜欢清晰度和单一源合并。


4

真正的问题不是嵌套视图本身。真正的问题是,随着开发人员在现有视图上进行其他调整,嵌套视图的泛滥。我发现带有嵌套视图4层的查询实际上嵌套到其定义中的视图之一。我们倾向于采用简单的方法而不是分析和解决问题,这是问题的根源。


0

在我的环境中,我们将许多表从生产服务器复制到报表服务器。在报表服务器上,我们有大量基于复制的生产表并嵌套的视图。在复制开始之前,我们必须删除所有视图以使复制成为可能(由于表结构在生产中经常发生变化,因此我们使用drop和create)。复制结束后,我们必须重建所有视图。

现在这里是有趣的部分:因为许多视图是嵌套的,所以我们必须按特定顺序重建它们。在对视图定义进行任何更改时,我们必须注意保持正确的重建顺序。真是一团糟。如果您使用复制或只是删除并重建表(这些视图的来源),我强烈不鼓励使用嵌套视图。

性能是另一回事。基于其他视图的视图只不过是要执行的多个查询。将较大的查询组合在一起,创建工作并从中创建表会更容易。更容易并提高性能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.