使用 VIEW 进行 SELECT 操作可以提高性能吗?

Posted

技术标签:

【中文标题】使用 VIEW 进行 SELECT 操作可以提高性能吗?【英文标题】:Can using a VIEW for SELECT operations improve performance? 【发布时间】:2009-02-26 14:02:32 【问题描述】:

在努力提高决策中心的性能时,我们发现的瓶颈之一是数据库。

所以我想知道,oracle 是否为它的视图编译了一个执行计划?

假设我有一个已定义的查询在请求期间被使用10000 次。 查询看起来像:

select A, B, C 
from aTbl, bTbl left join cTbl on bTbl.cTblID = cTbl.objectkey
where aTbl.objectkey = bTbl.parentkey

在代码中我想用附加的过滤参数来获取上面查询的结果,例如:WHERE aTbl.flag1 = <<NUMBER>>

现在我有两个选择:

    使用上述SQL 创建一个准备好的语句,然后重用该对象。 将上面的select (aTbl, bTbl, cTbl) 放入VIEW,然后在这个视图上创建一个prepared statement,从而受益于b Oracle 预编译的执行计划。

你有什么建议?

【问题讨论】:

【参考方案1】:

Oracle可以将谓词推送到视图中,如果它认为它会改进计划。

如果您想避免这种情况,您可以使用以下任一方法:

    在视图定义中添加/*+ NO_MERGE *//*+ NO_PUSH_PRED */ 提示 在使用视图的查询中添加/*+ NO_MERGE (view) *//*+ NO_PUSH_PRED (view) */ 提示。

如果您想强制执行此操作,请使用他们的 couterparts /*+ PUSH_PRED *//*+ MERGE */

就性能而言,使用已定义视图(当然,如果它不是 MATERIALIZED VIEW)或内联视图(即子查询)没有区别。

Oracle 编译计划不是为了查看,而是为了准确的SQL 文本。

即对于以下语句:

SELECT A, B, C 
FROM   aTbl, bTbl
LEFT JOIN cTbl ON 
  bTbl.cTblID = cTbl.objectkey
WHERE aTbl.objectkey = bTbl.parentkey
  AND aTbl.flag1 = :NUMBER

SELECT *
FROM
  (
  SELECT A, B, C, flag1
  FROM   aTbl, bTbl
  LEFT JOIN cTbl ON 
    bTbl.cTblID = cTbl.objectkey
  WHERE aTbl.objectkey = bTbl.parentkey
  )
WHERE flag1 = :NUMBER

/*
CREATE VIEW v_abc AS
SELECT A, B, C, flag1 
FROM   aTbl, bTbl
LEFT JOIN cTbl ON 
  bTbl.cTblID = cTbl.objectkey
WHERE aTbl.objectkey = bTbl.parentkey
*/

SELECT A, B, C
FROM v_abc
WHERE flag1 = :NUMBER

计划将:

    一样(如果Oracle会选择push谓词,这很有可能); 第一次调用时编译; 再次调用时重复使用。

【讨论】:

看来他是想让oracle去做,而不是回避。 谢谢您,我很抱歉忘记接受您的意见作为这个问题的答案。【参考方案2】:

视图并不是你真正想要的。

您想要做的是使用bind variables 作为您的标志条件;这样你就可以编译语句一次,并针对不同的标志执行多次。

就像一个风格说明 - 您应该决定如何指定连接,并遵循它,以保持一致性和可读性。照原样,你有 atbl 和 btbl 的显式连接条件,以及 btbl 和 ctbl 的“左连接”语法。在事情的方案中并不重要,但看起来和读起来有点奇怪。

祝你好运!

【讨论】:

【参考方案3】:

视图不会导致性能提升。有时它们可​​能会降低性能。我并不是说你应该避免观点;在使用它们之前只知道可能的影响。 Oracle documentation 说:

视图可以加快和简化应用程序设计。一个简单的视图定义可以掩盖数据模型的复杂性,避免程序员优先考虑检索、显示、收集和存储数据。

但是,虽然视图提供了简洁的编程接口,但它们可能会导致次优的资源密集型查询。最糟糕的视图使用类型是当一个视图引用其他视图时,以及它们在查询中加入时。在许多情况下,开发人员可以直接从表中满足查询,而无需使用视图。通常,由于视图的固有属性,优化器很难生成最佳执行计划。

【讨论】:

【参考方案4】:

我认为这不是您要寻找的,但如果底层表格不经常更改,例如每天或每小时,您可以使用物化视图。这基本上是一个存储的结果集。您还可以在它们上添加索引。它们可以按计划刷新,也可以在底层表发生变化时刷新(对于 OLTP 而言并非如此)。

Here is Oracle's docs on using materialized views.

【讨论】:

【参考方案5】:

Oracle 中没有“预编译”视图:从定义的视图中选择与直接从表中选择在性能方面没有什么不同(假设所有连接和条件都相同)。

当您说您的查询是“在请求期间被使用了 10000 次”时,我感到很困惑。这听起来不太理想 - 为什么会这样?

【讨论】:

他说的不是视图的预编译,而是执行计划。 (还有视图的预编译——它被称为物化视图......) 物化视图是物化,而不是预编译。预编译称为 STORED OUTLINE,甚至这也不是预编译 :) 物化视图本身并不是“视图”——它们是派生表,曾经被称为“快照”,这可能是一个更好的名称。【参考方案6】:

这里的答案是肯定的和否定的。

oracle 只会解析一个语句一次。关键是它必须是“相同的”,而不仅仅是相似。这包括间距(或制表符)和 cmets。

使用create view 创建视图允许您按原样修复语句并允许重用。

然而。

SELECT * FROM VIEWSELECT * FROM VIEW WHERE A=1

是 2 个不同的语句/查询。

要获得最大的语句重用,您必须使用绑定变量,而不仅仅是将条件连接到您的 SELECT。这通常意味着准备好的陈述

如果可以的话,你没有提到哪种宿主语言,如果可以的话,我会用一个具体的例子来更新。

在 PL/SQL 中

宣布 光标 c (cpflag aTbl.flag1%TYPE ) 是 选择 A、B、C 来自 aTbl、bTbl、cTbl 其中 aTbl.objectkey = bTbl.parentkey 和 bTbl.cTblID = cTbl.objectkey 和 aTbl.flag1 = cp_flag ; vtype c%rowtype; 开始 打开 c(100); 将 c 提取到 vtype 中; 关闭 c; 打开 c(200); 将 c 提取到 vtype 中; 关闭 c; 结尾;

在诸如 java 之类的准备语句中,您输入“?”作为占位符并使用 stmt.bind() 调用

希望对你有帮助

【讨论】:

以上是关于使用 VIEW 进行 SELECT 操作可以提高性能吗?的主要内容,如果未能解决你的问题,请参考以下文章

Mysql加锁过程详解-select for update/lock in share mode 对事务并发性影响

SQL Server 中 ROWLOCK 行级锁

[MSSQL]SQLServer之数据库行锁

优化程序性能——提高并行性

(45)C#里使用操作符重载来提高阅读性和性能

(45)C#里使用操作符重载来提高阅读性和性能