使用 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 VIEW
和SELECT * 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 操作可以提高性能吗?的主要内容,如果未能解决你的问题,请参考以下文章