【问题标题】:Is it OK to nest database views?嵌套数据库视图可以吗?
【发布时间】:2009-09-29 20:27:53
【问题描述】:

在 oracle 的世界中,我的印象是,基于其他观点的观点被认为是不好的做法。当试图解决性能问题和嵌套似乎过度并隐藏了底层视图中不必要的复杂性时,我自己就抱怨过这一点。现在我发现自己的情况可能不是那么明确:

我有一些用户非常需要从一个视图中获取会计编号,以匹配另一个对其进行进一步处理的会计编号。如果他们对其中的任何内容进行了更改,他们希望另一个立即反映这一点,而无需任何人在几年后考虑此要求,并且在他们解决问题时报告显示不匹配的数字。

这种情况下可以嵌套视图吗?

如果内部视图包含一个包含相关价格的更重要的视图(即您在确定价格时“总是”应该使用此视图),它会改变事情吗?

【问题讨论】:

  • +1,好问题,你可以看到很多意见。可能不是任何一刀切的答案。

标签: sql oracle plsql views


【解决方案1】:

嵌套视图的主要问题是查询优化器更容易混淆并产生次优计划。除此之外,在视图上使用视图没有特定的开销,除非它们做了优化器无法将谓词下推到的事情。

这意味着最好的选择是尝试嵌套视图。看看你是否从报告中得到了合理的查询计划。如果它确实会导致问题,那么您可能需要重新考虑您的策略。

【讨论】:

  • +1,回答此类问题的最佳方法是尝试并衡量性能影响。解释计划是你的朋友。
【解决方案2】:

我只是从最佳实践的角度来回答:

只有几次我会暂停使用 Views on Views。

  1. 嵌套似乎失控了......就像超过 3 层一样深。我嵌套的原因是使代码更易于维护。当我开始理解这一点时,它开始感觉有点太复杂了。

  2. 嵌套使用分析函数的视图。出于某种原因,我个人在具有分析功能的嵌套视图方面没有很好的经验。

  3. 嵌套视图自然会进行全面扫描。虽然我认为查询优化器可能足够聪明来处理这个问题,但当我查看视图的逻辑时,它对我来说似乎是错误的。

  4. 性能是一个很大的问题。这并不是说优化器可能会出错,而是说在我发布它之前,我会对其进行测试,看看我是否找不到更快的方法。

除此之外,我已经非常成功地使用了视图上的视图。

【讨论】:

    【解决方案3】:

    我认为您正处于代码重用和性能将发生冲突的滑坡上。您可以尝试一下,看看它对性能的影响有多大。我们这里有几个数据库,它们将视图堆叠在视图之上,坦率地说,性能很差,现在每个参与的人都希望他们没有那样设计。

    【讨论】:

    • 就像任何可以被滥用的东西一样。视图的真正好处是您可以在不影响界面的情况下更改实现(查询视图以及底层表结构)。我不会为了政策而盲目遵守政策。
    【解决方案4】:

    在编码时间、代码的易用性或质量以及性能之间总是需要权衡取舍。

    嵌套视图真的很容易编写代码,并且在适当的情况下使其易于阅读。它还可以减少时间。可以说它会降低质量并且通常会降低性能......但是会降低多少?

    这都是主观的。如果有道理,那就顺其自然吧。不要过早地优化你的代码。

    【讨论】:

      【解决方案5】:

      最佳实践并不总是涵盖所有内容。我认为你有一个明确的理由来嵌套它们,就这一次。

      【讨论】:

        【解决方案6】:

        我在 Oracle 10g R2 中嵌套了 3 个级别的视图。性能似乎与视图中的选择语句相关,而不是视图深度。特别是“IN”子句似乎造成了很多麻烦。

        【讨论】:

        • 'in' 在语义上等同于一系列 'or' 运算符。 'Or' 谓词是不可 sarg 的(SQL Server 术语,意思是谓词可以使用索引来解析),尽管现代优化器在将它们转换为可以通过这种方式解析的东西方面做得越来越好。
        【解决方案7】:

        在构建复杂的数据库查询的过程中要注意,有时嵌套视图是最好的事情 - 例如,如果您需要任何基于 2 列的数学运算符,例如 SUM(Col1, Col2) 它可以更好地嵌套视图,这样总和本身就是一列,而不必做类似

        的事情

        “选择总计 / SUM(Col1, Col2), SUM(Col1, Col2) * 2, Col1 / SUM(Col1, Col2) ..."

        但是我不确定我是否 100% 理解 - 为什么需要 2 个视图?不能两个用户都看第一个视图,并在该视图之上的另一层中派生进一步处理吗?

        【讨论】:

          【解决方案8】:

          使用视图的最佳理由是:

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

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

          【讨论】:

            【解决方案9】:

            嵌套视图是有意义的。请注意不要让它们过于笼统。


            我确实看到一个系统有一个视图,其中明确提到了 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_项目。 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 个外连接。

            【讨论】:

              【解决方案10】:

              真的不想陷入整个嵌套视图的事情

              考虑一下这个想法...您尝试加入表以查找不匹配...我将使用 Oracle 函数“减号”...。MINUS 从第一个表中选择元素,然后删除第二个 SELECT 语句也返回的行。

              选择号码 来自(选择 1 作为编号 从双 联合所有 选择 2 作为编号 从双 联合所有 选择 3 作为编号 FROM DUAL) base_view

              减号

              选择 2 作为编号 来自双重

              【讨论】:

              • 感谢您的回答,但这实际上不是我想要的 - 将有两个报告,每个报告列出不同类型的信息(通过分组),但它们需要完全匹配(总计)。它不用于检测差异,这两者都是为了各自的目的而必需的,但它们必须始终基于相同的数字,即使这些数字的规则将来会略有变化。
              猜你喜欢
              • 2012-01-12
              • 2013-09-11
              • 2010-09-07
              • 1970-01-01
              • 2015-09-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-03-16
              相关资源
              最近更新 更多