我很久以前在某个地方读过。这本书指出,我们不应该允许在 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
是基于今年入学的学生。学生符合条件的视图可以在其他地方使用,例如在存储过程中。
无论平台如何,以下备注均适用。
(-) 嵌套视图:
更难理解和调试
例如,该视图列指的是哪个表列?让我深入了解4 个级别的视图定义......
使查询优化器更难提出最有效的查询计划
有关轶事证据,请参见this、this、this和this。与此相比,这表明优化器通常足够聪明,可以正确解包嵌套视图并选择最佳计划,但并非没有编译成本。
您可以通过将视图查询与针对基表编写的等效查询进行比较来衡量性能成本。
(+) 另一方面,嵌套视图让您:
我发现它们很少需要。
在您的示例中,您使用嵌套视图来集中和重用某些业务定义(例如“什么是合格的学生?”)。这是嵌套视图的有效用途。如果您正在维护或调整此数据库,请权衡保留它们的成本与删除它们的成本。
保留:通过保留嵌套视图,您会产生上面列举的优点和缺点。
移除:移除嵌套视图:
您需要用它们的基本查询替换所有出现的视图。
如果您对合格学生/教师/学校的定义发生变化,您必须记住更新所有相关查询,而不是仅仅更新相关视图定义。
有时嵌套视图用于防止重复聚合。假设您有一个视图来计算消息并按用户 ID 对它们进行分组,您可能有一个视图来计算拥有 > 100 条消息的用户数量,诸如此类。当基本视图是索引视图时,这是最有效的 - 您不一定要创建另一个索引视图来表示具有稍微不同的分组的数据,因为现在您要为索引维护支付两次费用,而性能可能是足以反对原来的观点。
如果这些都只是嵌套视图,您正在执行 select * 但更改排序或顶部,那么与一堆嵌套视图相比,这似乎会更好地封装为带有参数(或内联表值函数)的存储过程。恕我直言。
更高版本的 SQL (2005+) 似乎更擅长优化视图的使用。视图最适合整合业务规则。EG:在我工作的地方,我们有一个电信产品数据库。每个产品都分配给一个费率计划,并且该费率计划可以换出,并且费率计划上的费率可以随着费率的增加或修改而被激活/停用。
为方便起见,我们可以制作嵌套视图。第一个视图只是使用所需的任何表将费率计划与其费率连接起来,并返回下一级视图所需的任何必要数据。2nd view(s) 只能隔离活动的费率计划及其活动费率。或者,只是客户费率。或员工费率(员工折扣)。或商业与住宅客户的价格。(利率计划可能会变得复杂)。关键是,基础视图确保我们的费率计划和费率的整体业务逻辑在一个位置正确连接在一起。下一层视图让我们更加关注特定的费率计划(类型、活动/非活动等)。
我同意如果您同时构建查询和视图,视图会使调试变得混乱。但是,如果您使用的是久经考验的可信视图,它会使调试变得更容易。您知道该视图已通过振铃器,因此您知道它很可能不会导致问题。
不过,问题可能会与您的观点相提并论。“如果一个产品只与一个非活动的利率计划相关联怎么办?” 或者“如果一个利率计划只有非活动利率怎么办?” 好吧,这可以通过捕获用户错误的逻辑在前端级别被捕获。“错误,产品处于非活动的价格计划中……请更正”。我们还可以在计费运行之前运行查询审计以仔细检查它。(选择所有计划并离开加入活动的利率计划视图,只返回没有获得活动利率计划的计划作为需要解决的问题)。
这样做的好处是视图可以让您大大压缩报告、计费等查询。您可以拥有客户帐户视图,然后是仅活跃客户的第二级视图。将其与客户地址结合起来。结合产品视图(加入客户拥有的产品)。团队查看产品费率计划。结合产品功能的观点进行团队合作。查看,查看,查看,每次试错以确保完整性。您使用视图的最终查询非常紧凑。
编辑:
作为一个示例,该视图将如何比仅对表进行平面查询更好……我们有一个临时承包商进来进行一些更改。他们告诉他对事情有看法,但他决定平息他所有的询问。Billing 正在处理他的一些查询。他们不断获得多个利率计划和利率。事实证明,他的查询缺少标准,仅允许在费率计划应该使用该费率/那些费率的开始和结束日期之间计费。哎呀。如果他使用视图,它就会考虑到这个逻辑。
基本上,您必须权衡性能与理智。也许您可以做各种花哨的事情来提高数据库的性能。但是,如果这意味着新人接管/维护是一场噩梦,那真的值得吗?真的值得新人玩whack-a-mole必须找到所有需要改变逻辑的查询(并冒着他忘记/胖手指的风险)b / c某人认为观点是“坏的”并且没有将一些核心业务逻辑整合到一个可以在 100 多个其他查询中使用的逻辑中?这完全取决于您的业务和您的 IT/IS/DB 团队。但是,比起性能,我更喜欢清晰和单一来源的整合。
真正的问题不是嵌套视图本身。真正的问题是嵌套视图的激增,因为开发人员对现有视图进行了额外的调整。我发现具有嵌套视图 4 层的查询实际上连接到其定义中的一个视图。我们倾向于采取简单的方法而不是分析和解决问题是问题的根源。
在我的环境中,我们将大量表从生产服务器复制到报告服务器。在报告服务器上,我们有很多基于复制的生产表并且是嵌套的视图。在复制开始之前,我们必须删除所有视图以使复制成为可能(我们使用 drop 和 create 因为表结构在生产中经常发生变化)。复制结束后,我们必须重建所有视图。
现在有趣的部分来了:因为许多视图是嵌套的,我们必须以特定的顺序重新构建它们。在对视图定义进行任何更改时,我们必须注意保持正确的重建顺序。真是一团糟。如果您使用复制或简单地删除并重建您的表,我强烈反对使用嵌套视图,这是视图的来源。
性能是另一回事。基于其他视图的视图只不过是要执行的多个查询。将更大的查询放在一起、创建作业并从中制作表格更容易。更容易并提高性能。