知识大全 Oracle更新操作优化
Posted 时间
篇首语:从来好事天生俭,自古瓜儿苦后甜。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Oracle更新操作优化相关的知识,希望对你有一定的参考价值。
Oracle更新操作优化 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
首先描述一下更新的要求 根据远端数据库中几张表的关联结果来刷新本地表中一个字段的值 如果本地表中记录的ID在远端表关联中可以查询的到 则这条记录的相应字段更新为 否则如果对应记录在远端无法查询到记录 则这个字段更新为
这个需求比较简单 但是被更新表是物化视图复制的基表 需要将修改复制到多个远端物化视图中 因此 为了避免将过多不必要的修改传播到远端站点 这里有一个额外的要求 只更新当前状态不正确的记录 也就是说 更新之前要判断更新前和更新后是否一样 只有二者不一样才需要更新
最后一点要求是不建立临时表 使用SQL或者PL/SQL来尽量高效的实现这个功能 不使用临时表的要求是处于两点考虑 一是由于需求本身很简单 写SQL或PL/SQL最多也就十几行而已 为这么简单的需求建立一个临时表没有什么必要;另外一点是由于当前数据库版本为 INSERT INTO SELECT插入临时表存在bug 产生的REDO比插入普通表还要高 详细情况可以参考 临时表产生REDO过多的bug
下面还是通过例子来详细说明
SQL> CONN YANGTK/YANGTK@YTK 已连接
SQL> CREATE TABLE T AS SELECT ROWNUM ID A * FROM DBA_OBJECTS A;
表已创建
SQL> ALTER TABLE T ADD PRIMARY KEY (ID);
表已更改
SQL> CREATE TABLE T AS SELECT ROWNUM ID B * FROM DBA_SYNONYMS B;
表已创建
SQL> CREATE INDEX IND_T _ID ON T (ID);
索引已创建
SQL> ALTER TABLE T MODIFY ID NOT NULL;
表已更改
SQL> CREATE TABLE T AS SELECT ROWNUM ID C OWNER C TABLE_NAME C COLUMN_NAME
FROM DBA_TAB_COLUMNS C;
表已创建
SQL> ALTER TABLE T ADD PRIMARY KEY (ID);
表已更改
SQL> EXEC DBMS_STATS GATHER_TABLE_STATS(USER T )
PL/SQL 过程已成功完成
SQL> EXEC DBMS_STATS GATHER_TABLE_STATS(USER T )
PL/SQL 过程已成功完成
SQL> EXEC DBMS_STATS GATHER_TABLE_STATS(USER T )
PL/SQL 过程已成功完成
SQL> CONN YANGTK/YANGTK@YTK 已连接
SQL> CREATE TABLE T AS SELECT ROWNUM ID OBJECT_NAME MOD(ROWNUM ) TYPE FROM DBA_OBJECTS A;
表已创建
SQL> ALTER TABLE T ADD PRIMARY KEY (ID);
表已更改
SQL> EXEC DBMS_STATS GATHER_TABLE_STATS(USER T )
PL/SQL 过程已成功完成
SQL> CREATE DATABASE LINK YTK CONNECT TO YANGTK IDENTIFIED BY YANGTK USING YTK ;
数据库链接已创建
在这个例子中 需要更新YTK 数据库中T表的TYPE字段 如果T表中一条记录的ID可以在远端T T T 表的联合查询中查询到 则这条记录的TYPE应该更新为 如果查询不到对应的记录 则需要更新TYPE的值为O 如果当前的TYPE的值已经满足要求 则不需要进行更新
最简单的方法莫过于更新两次 每次只更新一部分数据
SQL> SET TIMING ON SQL> BEGIN UPDATE T SET TYPE = WHERE TYPE = AND ID IN ( SELECT T ID FROM T @YTK T T @YTK T T @YTK T WHERE T ID = T ID AND T ID = T ID ); UPDATE T SET TYPE = WHERE TYPE = AND NOT EXISTS ( SELECT FROM T @YTK T T @YTK T T @YTK T WHERE T ID = T ID AND T ID = T ID AND T ID = T ID ); END; / PL/SQL 过程已成功完成
已用时间: : :
SQL> ROLLBACK;
回退已完成
已用时间: : :
当然 也可以通过一个UPDATE来实现更新 只不过逻辑略微复杂了一点
SQL> UPDATE T SET TYPE = ( SELECT TYPE FROM ( SELECT T ID DECODE(T ID NULL ) TYPE FROM T ( SELECT T ID FROM T @YTK T T @YTK T T @YTK T WHERE T ID = T ID AND T ID = T ID ) T WHERE T ID = T ID(+) AND T TYPE != DECODE(T ID NULL ) ) A WHERE T ID = A ID ) WHERE EXISTS ( SELECT FROM ( SELECT T ID DECODE(T ID NULL ) TYPE FROM T ( SELECT T ID FROM T @YTK T T @YTK T T @YTK T WHERE T ID = T ID AND T ID = T ID ) T WHERE T ID = T ID(+) AND T TYPE != DECODE(T ID NULL ) ) A WHERE T ID = A ID ) ; 已更新 行
已用时间: : :
SQL> ROLLBACK;
回退已完成
已用时间: : :
有的时候 一个复杂的SQL并不比两个简单的SQL效率要高 上面就是一个例子 这里的主要原因是 无论是两次更新 还是一个UPDATE语句 对远端的两个表访问两次是无法避免的 而一个UPDATE的逻辑更加复杂 选择执行计划更加困难
由于访问远端对象的代价是相对比较大的 下面通过PL/SQL的方式来避免对远端对象的多次访问
SQL> DECLARE V_TYPE NUMBER; BEGIN FOR I IN (SELECT ID TYPE FROM T) LOOP SELECT DECODE(COUNT(T ID) ) INTO V_TYPE FROM T @YTK T T @YTK T T @YTK T WHERE T ID = T ID AND T ID = T ID AND T ID = I ID; IF I TYPE != V_TYPE THEN UPDATE T SET TYPE = V_TYPE WHERE ID = I ID; END IF; END LOOP; END; / PL/SQL 过程已成功完成
已用时间: : :
SQL> ROLLBACK;
回退已完成
已用时间: : :
目前的效率已经基本可以了 但是对于数据量比较大的情况 这种方式效率仍然比较低 虽然对远端表只读取一次 但是在循环中进行这个操作效率肯定要比直接通过SQL执行低 而且对于每个匹配的记录执行一次UPDATE 这也是比较低效的 修改PL/SQL代码 通过批量处理的方式来执行
SQL> DECLARE TYPE T_ID IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; TYPE T_TYPE IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; V_ID T_ID; V_TYPE T_TYPE; BEGIN SELECT T ID DECODE(T ID NULL ) TYPE BULK COLLECT INTO V_ID V_TYPE FROM T ( SELECT T ID FROM T @YTK T T @YTK T T @YTK T WHERE T ID = T ID AND T ID = T ID ) T WHERE T ID = T ID(+) AND T TYPE != DECODE(T ID NULL ) ; FORALL I IN V_ID COUNT UPDATE T SET TYPE = V_TYPE(I) WHERE ID = V_ID(I); END; / PL/SQL 过程已成功完成
已用时间: : :
SQL> ROLLBACK;
回退已完成
已用时间: : :
通过运用PL/SQL减少远端对象的访问次数和批量操作的运用 整个过程的执行时间已经从原来的 多秒优化到了 秒 如果这时候检查执行计划可以发现 由于是对本地的更新 Oracle选择当前站点作为驱动站点 且对远端三个表的查询采用了NESTED LOOP 如果使用HINT来规定驱动站点和HASH JOIN连接方式 还是获得一定的性能提升
SQL> DECLARE TYPE T_ID IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; TYPE T_TYPE IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; V_ID T_ID; V_TYPE T_TYPE; BEGIN SELECT T ID DECODE(T ID NULL ) TYPE BULK COLLECT INTO V_ID V_TYPE FROM T ( SELECT /*+ DRIVING_SITE(T ) USE_HASH(T T ) USE_HASH(T ) */ T ID FROM T @YTK T T @YTK T T @YTK T WHERE T ID = T ID AND T ID = T ID ) T WHERE T ID = T ID(+) AND T TYPE != DECODE(T ID NULL ) ; FORALL I IN V_ID COUNT UPDATE T SET TYPE = V_TYPE(I) WHERE ID = V_ID(I); END; /
PL/SQL 过程已成功完成
已用时间: : :
SQL> ROLLBACK;
回退已完成
已用时间: : :
从 秒提高到 秒 效果似乎并不明显 不过执行时间已经缩短了 % 对于大数据量的情况 这个 %的性能提高会十分客观
通过这个例子想说明几个问题
第一 Tom所说的能使用一条SQL就用一条SQL完成 不能使用SQL的话 可以使用PL/SQL完成 这句话在大部分的情况下是正确的 但是并不意味着SQL一定比PL/SQL快 单条SQL一定比两个SQL快 上面的例子很好的说明了这个问题
第二 批量操作一般情况下要比PL/SQL循环效率高 上面的例子中就通过循环和批量两种方法对比很好的说明了这个问题 但是认为批量操作就一定比循环操作快 对于例子中的两个SQL调用 都可以认为是一个批量操作 但是由于对远端表访问了两次 效率远远低于只访问远端对象一次的循环操作
cha138/Article/program/Oracle/201311/17339相关参考
Oracle游标的删除与更新实际操作步骤 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 以下的文
Oracle中操作系统优化和使用资源管理器 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 操作系
使用资源管理器优化Oracle性能 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 操作系统优化
Oracle提供免费OracleLinux更新源 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
Oracle作业(JOB)更新next 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 摘要:本文
所有的MIS系统都存在一个同样的需求就是对于特定的数据在一次批量操作过程中如果数据已经存在则对存在的数据按照现有情况进行 更新如果不存在则需要加入数据库这时我们就可以考虑采用Oracle的MER
Oracle多表级联更新详解 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!我们在平时的工作中可能遇
概括Oracle优化器的优化方式 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! Oracle是世
Oracle中的Merge函数(批量更新/删除) 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
讲解Oracle优化器的优化方式和优化模式 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! Ora