嵌套数据库视图是否可行?

9
在Oracle的世界里,我认为基于其他视图的视图被认为是不良实践。当我试图解决性能问题时,我自己也抱怨过这个问题,嵌套似乎过多,并且在底层视图中隐藏了不必要的复杂性。现在我发现自己处于这样一种情况下,认为可能并不是那么清晰明确:
我有一些用户非常需要一个视图的会计数字与另一个视图进行匹配,后者对它们进行进一步处理。如果他们在其中一个视图中做出任何更改,他们希望另一个视图立即反映出来,而无需在几年后考虑此要求,同时显示不匹配的数字并找出问题。
在这种情况下嵌套视图是否可以接受?
如果内部视图包含一个重要的视图,其中包含相关价格(即在确定价格时“总是”应该使用此视图),这是否会改变事情?

1
+1,好问题,众说纷纭,正如您所见。可能没有一个适用于所有情况的答案。 - DCookie
10个回答

8

嵌套视图的主要问题在于查询优化器更容易混淆并产生次优计划。除此之外,使用视图嵌套没有特定的开销,除非它们执行某些优化器无法将谓词下推到的操作。

这意味着最好的选择是尝试使用嵌套视图。查看报告是否能得到合理的查询计划。如果出现问题,则可能需要重新考虑您的策略。


4
最好的回答这类问题的方法是尝试并测量性能影响。解释计划是你的好朋友。 - DCookie

5

从最佳实践的角度来看,我会这样回答:

只有在以下几种情况下,我才会考虑使用 Views on Views。

  1. 嵌套似乎已经失控...超过 3 层深度。我嵌套的原因是为了使代码更易于维护。一旦我开始达到这个点,它就开始感觉有点太复杂,难以理解。

  2. 嵌套一个使用分析函数的视图。出于某种原因,我个人对嵌套带有分析函数的视图没有很好的体验。

  3. 嵌套视图本质上进行全表扫描。虽然我认为查询优化器可能足够聪明,能够处理这个问题,但当我审查视图的逻辑时,它看起来就不对劲。

  4. 性能是一个非常重要的问题。这并不是说优化器可能会出错,而是在发布之前,我会测试它,看看是否能找到更快的方法来完成它。

除此之外,我已经成功地使用了 Views on Views。


4

我觉得你现在正处于代码重用和性能冲突的滑坡上。你可以尝试一下,看看它会对性能产生多大的影响。我们这里有几个数据库,它们在视图之上堆叠了视图,说实话性能很糟糕,现在所有相关人员都希望他们当初没有那样设计。


3
就像任何东西一样,它都可能被滥用。视图的真正好处在于你可以更改实现方式(查询视图以及底层表结构),而不会影响接口。我不会为了遵循政策而盲目跟随。 - David

2

在编码时间、代码的易读性和质量以及性能之间总是存在一种权衡。

嵌套视图很容易编写,并在合适的情况下使代码易于阅读。它也可以减少时间。这可以说降低了代码质量,而且经常会降低性能...但降低了多少?

这都是主观的。如果有意义,请继续使用。不要过早地优化您的代码。


1
最佳实践并不总是覆盖所有情况。我认为,你有一个明确的理由来嵌套它们,只是这一次而已。

1

我在Oracle 10g R2中嵌套了3层视图。性能似乎与视图深度无关,而与视图中的select语句有关。特别是,“IN”子句似乎引起了很多麻烦。


3
“in”在语义上等同于一系列的“or”运算符。 “Or”谓词(predicate)不可被sarg-able(SQL Server术语,意味着可以使用索引解析谓词),尽管现代优化器越来越擅长将它们转换为可以以这种方式解析的内容。 - ConcernedOfTunbridgeWells

0

嵌套视图可能是有意义的。只要小心,不要让它们变得太普遍。


我曾经看到一个系统,其中一个视图明确提到了14个表,其中一些通过外部自连接相互关联,而一些“表”本身就是视图。我不太喜欢它,但是DBMS(数据库管理系统)处理得非常出色(考虑到那是在80年代末)。很多模式都是由数据建模工具自动生成的。

CREATE VIEW IBB_V_Project AS
    SELECT  A.Project_Iref,
            A.Section_Iref,
            B.Section_Eref,
            N.Company_Iref,
            N.Company_Name,
            A.Product_Desc,
            A.Project_Type_Iref,
            D.Project_Type,
            A.Person_Iref,
            F.Full_Name,
            A.Respon_Iref,
            G.Post_Location,
            A.Project_Stat_Iref,
            E.Project_Status,
            A.Source_Iref,
            I.Source,
            A.Sic_Iref,
            L.Sic_Eref,
            A.Op_Activity_Iref,
            M.Op_Activity_Desc,
            A.Involve_Iref,
            K.IBB_Involvement,
            A.Nature_Iref,
            C.Nature_Of_Next_Act,
            A.Internat_Mobile,
            A.Whether_Cop_Case,
            A.Closed_Ind,
            A.Next_Action_Date,
            A.Creation_Date,
            A.Last_Edit_Date,
            A.Last_Editor_Iref,
            H.Logname

    FROM    IBB_Project A,
            IBB_Section B,
            IBB_R_Proj_Type D,
            IBB_R_Project_Stat E,
            IBB_Personnel H,
            OUTER IBB_R_Next_Act C,
            OUTER IBB_Personnel F,
            OUTER (IBB_Post_Respon X, OUTER IBB_V_Post_Resp2 G),
            OUTER IBB_R_Source I,
            OUTER IBB_R_Involvement K,
            OUTER IBB_Sic L,
            OUTER IBB_Op_Act M,
            OUTER IBB_V_Proj_Co2 N

    WHERE   A.Section_Iref      = B.Section_Iref
      AND   A.Project_Type_Iref = D.Project_Type_Iref
      AND   A.Project_Stat_Iref = E.Project_Stat_Iref
      AND   A.Last_Editor_Iref  = H.Person_Iref
      AND   A.Nature_Iref       = C.Nature_Iref
      AND   A.Person_Iref       = F.Person_Iref
      AND   A.Respon_Iref       = X.Respon_Iref
      AND   X.Respon_Iref       = G.Person_Iref
      AND   A.Source_Iref       = I.Source_Iref
      AND   A.Sic_Iref          = L.Sic_Iref
      AND   A.Op_Activity_Iref  = M.Op_Activity_Iref
      AND   A.Project_Iref      = N.Project_Iref
      AND   A.Involve_Iref      = K.Involve_Iref;

外连接符号是Informix特有的(现在也支持SQL标准符号)。

请注意,IBB_V_Post_Resp2和IBB_V_Proj_Co2本身都是视图。 实际上,IBB_V_Proj_Co2是一个3个表的视图,具体细节未知,但形式为:

CREATE VIEW IBB_V_Proj_Co2 AS
    SELECT  A.Project_Iref,
            A.Some_Other_Col col01,
            B.Xxxx_Iref,
            B.Some_Other_Col col02,
            C.Yyyy_Iref,
            C.Some_Other_Col col03
    FROM    IBB_Project A,
            OUTER (IBB_R_Xxxx B, IBB_R_Yyyy C)
    WHERE   A.Xxxx_Iref = B.Xxxx_IrEf
      AND   B.Yyyy_Iref = C.Yyyy_Iref;

这意味着IBB_V_Project视图在IBB_Project上有一个外部自连接。 IBB_V_Post_Resp2视图可能也涉及3个表(当我记录这些信息时,已经是1993年了,我的笔记有点不清楚)。

CREATE VIEW IBB_V_Post_Resp2 AS
    SELECT  A.Person_Iref,
            A.Some_Other_Col col01,
            B.Xxxx_Iref,
            B.Some_Other_Col col02,
            C.Yyyy_Iref,
            C.Some_Other_Col col03
    FROM    IBB_Personnel A,
            IBB_R_Xxxx B,
            IBB_R_Yyyy C
    WHERE   A.Xxxx_Iref = B.Xxxx_Iref
      AND   B.Yyyy_Iref = C.Yyyy_Iref;

Zzzz_Iref列是SERIAL或INTEGER外键,引用了一个SERIAL键。

主视图定义涉及14个表,包括4个内连接和9个外连接。当考虑到交叉引用的视图时,总共有18个表,包括7个内连接和10个外连接。


0

在构建复杂数据库查询的过程中,有时嵌套视图是最好的选择。例如,如果您需要在两列上运算(如SUM(Col1, Col2)),则将此Sum作为一列嵌套在视图中可能比像下面这样进行处理更好:

"SELECT Total / SUM(Col1, Col2), SUM(Col1, Col2) * 2, Col1 / SUM(Col1, Col2) ..."

不过我并不确定是否完全理解——为什么需要两个视图?难道两个用户不能查看同一个视图,并在其上层的另一个视图中进行进一步处理吗?


0

使用视图的最好理由是:

  1. 防止重复查询相同的数据。
  2. 防止其他查询编写者直接访问表格。
  3. 创建一个安全层(类似于#2)。

我确实意识到它也可以帮助简化更复杂的查询,但你会习惯它。您可能会发现用户定义的函数(表格)是更好的解决方案。无论哪种方式,性能都会受到影响。


0

不想被纠缠在整个嵌套视图的事情上。

思考一下这个点子......你正在尝试加入一个表来查找不匹配的地方......我会使用 Oracle 函数“minus”....MINUS 从第一个表中选择元素,然后删除也由第二个 SELECT 语句返回的行。

SELECT num FROM (SELECT 1 AS num FROM DUAL UNION ALL SELECT 2 AS num FROM DUAL UNION ALL SELECT 3 AS num FROM DUAL) base_view

MINUS

SELECT 2 AS num FROM DUAL


谢谢回答,但这实际上不是我想要的 - 将有两份报告,每份报告都列出不同种类的信息(通过分组),但它们需要完全匹配(总数)。 这不是用于检测差异,它们都需要用于自己的目的,但无论这些数字的规则将来如何略微变化,它们必须始终基于相同的数字。 - Galghamon

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