表架构
常见数据库:
ORACLE、DB2、SQLSERVER 、MYSQL、INFORMIX、SYBASE、GBASE、南大金仓、达梦、NOSQL、MANQODB、KEV-VALUE、HADOOP
ORACLE是什么架构的数据库?
1、是关系型数据库(表与表之间有关系:体现方式如下:a.id=b.id)
2、ORACLE是行存储的数据库
行存储有什么优点:
比如银行或者即时交易 的数据库必须用行存储数据库。如果用列存储,插入一行,就会导致所有的列全部重新分布。原因是你按照列存储的,一个列的值肯定是重复的值比较多,是不是适合做压缩。
你用列存储去UPDATE ,DELETE ,INSERT 它是不是会把所有行给锁住。所以说列存储DB不能并发。
行存储支持大量的DML,支持复杂SQL,支持业务复杂的查询
列存储有什么优点:
一个列是不是重复值特别多,一个表的列是不是很多。列存储数据库一个人插入的时候,其他人就不能插入。
OLAP数据仓库有没有DML 很少是吧。如果用ORACLE作数据仓库,是不是表特别大,
行存储要让SQL跑得快,最牛B的就是做业务设计、表设计
如果 用 列存储数据库 尽可能的 怎么设计表?
尽可能把所有功能整合到一个大表中去,避免关联。
一行一行的存储的数据,重复值是不是很少?而且一行一行的存储,基本都是在一个块一个块中。普通的ORACLE也可以压力,但压缩比例很少。比如一个表10G,最多压缩到6-8G。DML很频繁的表也不能压力,压缩就死人。ORACLE索引可以压缩吗?可以的哈。
列存储数据库也是按块存储,一个块存储的是列数据。既然是存的列的数据,大家想一想,一个列的数据是不是重复值非常多。这个时候作压缩是不是非常明显。一般来说都可以压缩到7倍以上。一个表,在ORACLE中有7G,在列存储中可能就1个G,最多两个G。因为列存储是按列压力,ORACLE是按表压缩。在ORACLE中你要扫描10G,你用列存储就扫描1个G。而性能就会提高10倍。当然ORACLE可以建索引。
假设一个表列非常多,比如100个列的表,10GB。而在列存储中可能就1个G。一般我不可能全部访问,最多访问20个列。如果是ORACLE还是需要把整体表,10G给扫描了,而用列存储就只访问需要的列。也就是1G/5=200M。也就是说ORACLE要扫描10G,列存储只扫描200M,是不是秒杀了。还有更的,ORACLE数据库可以对一个列或者多个列建索引。而列存储数据库需要建索引吗?我们建索引是为了减少扫描列,通过where条件列来进行范围扫描。而列存储 数据库单个列都是自己建了索引的。多个列也不需要建索引,因为它单个列自带了索引,可以自己组合起来。所以说列存储数据库更绝的就是不建索引。列存储用作OLAP特别牛B。列存储优化就是通过业务设计和表设计来优化。
列存储数据库一般是采用什么架构?
ORACLE是share disk共享磁盘的架构。而列存储是share nothing架构。而sysbase IQ是个奇葩,是shre disk架构,最新版本才支持share nothing.
RAC要配置共享磁盘,为什么ORACLE要用RAC架构。因为ORACLE它是行存储的,行存储的数据库一个表存在哪个地方? 是不是都存储在同样一个存储上面。share nothing架构是一个表存储在多个节点,每个节点都有自己的存储。
share disk 存储是共享的 share nothing 存储是分开的(分布式架构)
如果我现在有10个节点,列存储数据库中是不是10个节点里面都要存储数据。刚才说了列存储里面压缩了只有1个G的表,而这1个G的表是不是分布在10个节点,也就是说每个节点存100M。但是我又不需要把100M数据全读了,说白了我只需要读每个节点的20M,我靠,这相当于开了10个并行,直接秒杀了。这就是列存储的强大效果。又压缩,又并行,能不快吗?列存储做OLAP,如果是单表访问,基本上全都是秒杀。
用ORACLE数据库最担心的就是I/O,我们去买存储一般买什么存储,是不是要考虑RAID10,IOPS高,MBPS
。
如果用列存储就买个垃圾磁盘就行了,因为I/O都缩小、分散了。节点越多什么是瓶颈?只能是网络对吧。
下面来说说列存储的缺点:
1、
DML
2、扩容,比如我以前有10个节点,现在搞成11个节点,是不是其他数据库中库的数据就会迁移一部分到新节点。所以说扩容就死。不能实时,只能关机。
3、某一个节点挂了,是不是整个系统全挂。这个时候可靠性又来了。节点越多出问题的机率就越大。所以share nothing架构是不是每个节点都要备份啊,并且都要作镜像。我有10个节点,是不是要搞20台机器。而这20台机器互为镜像,这时投入是不是超大了。虽然说买的是垃圾存储,但这些投入加起来,已经差不我可以买一个牛B机器了。这么多机器,另外是不是管理起来TM的特别麻烦了,简直不能叫特别,是TM超级。
4、表设计TM要特别重要,刚才说的主要是单表访问。列存储表设计一定最好是单表,统统搞成单表才行。但是列存储也没法干掉关联啊。如果多表关联呢?
select 几个列 from a, b where a.id=b.id;
|
A和B是不是要分别存储到10个节点里面。那作关联的时候要关联几次?是不是单个结点作关联,然后进行汇总。你一个表要分布到10个节点里面,是不是要按照某个KEY来分布,对吧。这时我们如果是按照ID列分布的,这个SQL就可以每个节点自己关联,再汇总。但是一个表是不是特别复杂。比如,我现在又要A和C关联。
select 几个列 from a, b where a.xx=c.xx
|
A通过ID和B关联,通过XX和C关联。但是如果C.XX我在本地机器找不到,
这时怎么办?是不是要先把A全部读出来,再通过XX列重新分布,写到临时表。如果内存够用还好。如果内存不够,或者用的人多了,就傻B了。所以列存储数据库不支持比较高的并发。而且复杂的业务也不知道选谁当分布键。只能关联了就重新分布数据。所以share nothing架构最重要的
就是设计要避免关联,尽量单表。这样基本上就不会出现问题。这也是为什么列存储架构非常优秀,但使得的人不多的原因。
混合型数据坚决不能用。。业务复杂的也不能用。因为业务复杂,关联SQL就复杂。
ORACLE
大表就并行HASH
大表小表就广播
任何数据库都要收集统计信息
目前最牛B的两个DB解决方案:
1、EXADATA 2、HANA
最牛B的数据库 EXADATA
EXADATA是什么架构?
是shre disk 架构。从架构上来说它支持7*24 有HA的作用。
EXADATA的存储也是按行存储,所以支持OLTP/OLAP
EXADATA搞了一个最底层存储软件,CELL,按照列存储。但是ORACLE实例并不知道它是按照列存储的。
这时事实它是行列混合存储。表面是行,底层是列。
所以EXADATA不需要建索引了。
一个表不建索引,是不是作批量导入这些就非快了。0延时插入。
HANA用的SYSBASE IQ,现在结合了另外一个数据库了。真正PK性能 ,HANA比EXADATA更快。
一定要注意表与表之间的关系,是一对一还是一对多
举例:
我们现开发一个类QQ的软件:
首先要创建用户表:
给字段取名字,确定字段类型,字段长度限制
怎么实现好友功能:
好友肯定是一对多对吧。一个人肯定会有上百上千的好友。
这时我们是不是需要再搞一个表出来,而这个表与用户表是什么关系,是不是一对多的关系。而 我们新创建的关系表一定要有哪些字段?
1、首先要有一个主键对吧,主键一般用ID嘛。
2、新创建的表既然是关系。用户表的ID肯定就在用户表了对吧。而我关系表已经有ID了。是不是还要有个好友ID。再加上加好友的时间。
3、好友分组,是不是加一个字段,作了标签就行了。
4、群功能。一个群号是唯一的。群号和人是什么关系。一个群对应多个人,是不是又要搞一个表出来了。
你要申请 一个群,QQ就要往DB里插入一条数据。记录表名,
创建人,公告之类的。而某些人要加这个群,是不是又要搞一个关系表了。就是群和人的关系表。也是一对多。群的关系表就是群的ID,用户ID,群等级,群名片
做表设计,读懂需求就对了。先不要管性能,先实现需求。表设计好了,写SQL的时候再考虑该合并,合并 ,该拆分,拆分
另外最关键的就是搞清楚一对一还是一对多。
案例:利用ROWID 提升查询性能
ETL 开发人员发来邮件说,能不能想办法 提升一下如下update语句的性能
UPDATE OPT_ACCT_FDIM A
SET ACCT_SKID = (SELECT ACCT_SKID
FROM OPT_ACCT_FDIM_BKP B
WHERE A.ACCT_ID = B.ACCT_ID);
SELECT COUNT(*) FROM OPT_ACCT_FDIM; -------这个表 有 226474 条数据
SELECT COUNT(*) FROM OPT_ACCT_FDIM_BKP; ------ 这个表 有 227817 条数据
SELECT COUNT(*)
FROM OPT_ACCT_FDIM A, OPT_ACCT_FDIM_BKP B
WHERE A.ACCT_ID = B.ACCT_ID
AND A.ACCT_SKID <> B.ACCT_SKID; -------要更新 226474 条
SELECT COUNT(*) FROM OPT_ACCT_FDIM a
WHERE EXISTS (SELECT 'x' FROM OPT_ACCT_FDIM_BKP b WHERE A.ACCT_ID = B.ACCT_ID ); 这个才是正确的
WHERE EXISTS (SELECT 'x' FROM OPT_ACCT_FDIM_BKP b WHERE A.ACCT_ID = B.ACCT_ID ); 这个才是正确的
那么现在已经很清楚了,业务逻辑就是根据 根据2个表的acct_id 字段关联,然后根据B表的字段update A表,那么这里呢 要更新整个A表
UPDATE的执行计划我们就不用看了,肯定是HASH JOIN,开发人员说 这个update 跑了30分钟,还没完成,其实我估计 这个SQL至少得1小时才能跑完。
其实,select 语句是很好优化的,但是update,delete这样的SQL, 如果要想从SQL上面优化,几乎不可能,优化update,delete我们要用PL/SQL来实现。
对于我们这里的UPDATE语句,我们可以利用rowid 来快速更新,PL/SQL 代码如下:
SQL> DECLARE
2 CURSOR CUR_B IS
3 SELECT
4 B.ACCT_ID, B.ACCT_SKID, A.ROWID ROW_ID
5 FROM OPT_ACCT_DIM A, OPT_ACCT_DIM_BKP B
6 WHERE A.ACCT_ID = B.ACCT_ID
7 ORDER BY A.ROWID; ---如果表的数据量不是很大,可以不用 order by rowid
8 V_COUNTER NUMBER;
9 BEGIN
10 V_COUNTER := 0;
11 FOR ROW_B IN CUR_B LOOP
12 UPDATE OPT_ACCT_DIM
13 SET ACCT_SKID = ROW_B.ACCT_SKID
14 WHERE ROWID = ROW_B.ROW_ID;
15 V_COUNTER := V_COUNTER + 1;
16 IF (V_COUNTER >= 1000) THEN
17 COMMIT;
18 V_COUNTER := 0;
19 END IF;
20 END LOOP;
21 COMMIT;
22 END;
23 /
PL/SQL procedure successfully completed.
Elapsed: 00:01:21.58
现在多快啊,1分22秒搞定
其实,以前的update就相当于下面的PL/SQL代码:
declare
cursor c_update is
select b.acct_skid, a.acct_id
from opt_acct_fdim a, opt_acct_fdim_bkp b
where a.acct_id = b.acct_id;
v_counter number;
begin
v_counter := 0;
for v_row in c_update loop
update opt_acct_fdim
set acct_skid = v_row.acct_skid
where acct_id = v_row.acct_id; ---注意,这里没有rowid
v_counter := v_counter + 1;
if (v_counter >= 1000) then
commit;
v_counter := 0;
end if;
end loop;
commit;
end;
/
我自己测试了一下上面的PL/SQL 代码,跑了30分钟没跑完,为什么跑这么久呢?
其实原因就在于这里:
update opt_acct_fdim
set acct_skid = v_row.acct_skid
where acct_id = v_row.acct_id;
因为缺少 rowid定位,那么又会对表进行全表扫描,而且每更新一行就会去做全表扫描。
而我们利用rowid定位block,那么不用 全表扫描了 性能提升上 百倍。
12 UPDATE OPT_ACCT_DIM
13 SET ACCT_SKID = ROW_B.ACCT_SKID
14 WHERE ROWID = ROW_B.ROW_ID;
其实这本书 Oracle Database 10g PL/SQL 程序设计 ---清华大学出版社 p132页 里面就有这个方法
itpub 这篇帖子:http://www.itpub.net/viewthread.php?tid=1052077 也提到过这个方法
总结:对于大批量的update,delete,我们可以利用rowid 来进行优化,性能往往提升 上百倍。
怎么去检查要更新多少行数据???
SELECT COUNT(*) FROM OPT_ACCT_FDIM a
WHERE EXISTS (SELECT 'x' FROM OPT_ACCT_FDIM_BKP b WHERE A.ACCT_ID = B.ACCT_ID ); 落总原来的那个是错误的, 这个才是正确的
WHERE EXISTS (SELECT 'x' FROM OPT_ACCT_FDIM_BKP b WHERE A.ACCT_ID = B.ACCT_ID ); 落总原来的那个是错误的, 这个才是正确的
UPDATE OPT_ACCT_FDIM A
SET ACCT_SKID = (SELECT ACCT_SKID
FROM OPT_ACCT_FDIM_BKP B
WHERE A.ACCT_ID = B.ACCT_ID);
从A里面取一条,传到子查询中去,然后再把A更新了。就是NL对吧。
B表是什么表,新创建的备份表,没有任何索引。因为这是TEMP中的备份表,肯定没有索引。而B表要被扫描A表总行数那么多次。B本来只有22W行,我们假设它有100M。意思就是跑个SQL 就有22W*100M这么多的I/O,所以说为什么这个SQL跑不出结果?
这个SQL不改代码怎么搞?
不改代码,B表始终要被搞22W次。我们是不是要想方设少减少B的体积。B要访问几个字段,是不是只访问两个列,这时我们建索引,NL的被驱动表是不是连接列在前。所以应该这样建
(ACCT_ID,ACCT_SKID)。这时通过索引当表用确实可以提高很多倍的性能。最优化的方法,是不是让两个都只扫描一次。
注意:UPDATE 主表 set OOXX =(select OOXX.....),当括号时面有主表连接条件的SQL只能走NL
禁止 写 update ....where (子查询 跟主表 的 连接条件 或者过滤条件),如果非要这样写就必须改成merge into
提问:
刚才的UPDATE 能开并行的吗?PLSQL能开并行吗?
答:PLSQL是不能开并行的。第一个UPDATE语句是可以开并行的,它会自动切片。但是这个并行很垃圾,因为B表要走索引,而索引没法并行。INDEX RANGE SCAN 是无法并行的
批量更新,MERGE语句性能最好,因为它可以多块读,并且可以并行执行,但是缺点就是消耗比较多的UNDO,一旦down机死事物恢复较慢。
ORDER BY ROWID 在 buffer cache 不够大的情况下性能较好好(没Merge快,因为Merge可以多块读,走ROWID只能单块读)。
优点就是可以批量提交。缺点就是不能并行更新。
不 ORDER BY ROWID 在 buffer cache足够大(能确保被更新的表不被page out) 的情况下性能较好。
create table a as select * from dba_objects;
create table b as select * from dba_objects;
insert into b select * from b; --- 直到插入60W数据
SQL> SELECT COUNT(*) FROM B;
COUNT(*)
----------
616864
SQL> SELECT SUM(BYTES)/1024/1024 "SIZE(MB)" FROM DBA_SEGMENTS WHERE SEGMENT_NAME='B';
SIZE(MB)
----------
72
create index idx_a on a(object_name,object_id);
create index idx_b on b(object_id);
比如要执行这个update b set b.object_name=(select a.object_name from a where a.object_id=b.object_id);
可以用MERGE代替
-------------------------MERGE版本,使用MERGE一定要确保MERGE into 的表走全表扫描----------------
alter session set db_file_multiblock_read_count=128;
如果要更新的表很大,alter session enable parallel dml;
alter session set workarea_size_policy=manual;
alter session set sort_area_size=xxx;
alter session set hash_area_size=xxx;
merge /*+ USE_HASH(C,H) FULL(C) */ into b c
using (select /*+INDEX(A) USE_HASH(A) */ a.object_name, a.object_id
from a
where a.object_id in (select /*+ use_hash(b) index(b) */ object_id from b)) h
on (c.object_id = h.object_id)
when matched then
update set c.object_name = h.object_name;
select * from table(dbms_xplan.display);
也可以写PL/SQL
-------------------------PL/SQL版本---------------------------------
DECLARE
CURSOR CUR_B IS
SELECT a.object_id, a.object_name, b.ROWID ROW_ID
FROM A, B
WHERE A.object_id = B.object_id
ORDER BY B.ROWID;
V_COUNTER NUMBER;
BEGIN
V_COUNTER := 0;
FOR ROW_B IN CUR_B LOOP
UPDATE b SET object_name = ROW_B.object_name WHERE ROWID = ROW_B.ROW_ID;
V_COUNTER := V_COUNTER + 1;
IF (V_COUNTER >= 10000) THEN
COMMIT;
dbms_output.put_line('Updated: ' ||V_COUNTER || ' lines.');
V_COUNTER := 0;
END IF;
END LOOP;
COMMIT;
END;
/
下面这个版本是批量处理的版本
------------------------批量处理版本--------------------------------
declare
maxrows number default 100000;
row_id_table dbms_sql.urowid_table;
--currcount_table dbms_sql.number_Table;
object_name_table dbms_sql.varchar2_Table;
cursor cur_b is
SELECT /*+ index(a) use_hash(a,b) index(b) */
a.object_name, b.ROWID ROW_ID
FROM A, B
WHERE A.object_id = B.object_id
ORDER BY B.ROWID;
v_counter number;
begin
v_counter := 0;
open cur_b;
loop
EXIT WHEN cur_b%NOTFOUND;
FETCH cur_b bulk collect
into object_name_table, row_id_table limit maxrows;
forall i in 1 .. row_id_table.count
update b
set object_name = object_name_table(i)
where rowid = row_id_table(i);
commit;
end loop;
end;
/
关于ORDER BY ROWID提升速度的验证
-------------------Buffer cache 不够大---------------------------------------
buffer cache 40Mb,B表有72Mb 所以不够存放下 B
keep pool 52Mb--keep idx_a,idx_b
SQL> alter system flush buffer_cache;
系统已更改。
已用时间: 00: 00: 00.00
SQL> merge into b c
2 using (select a.object_name, a.object_id
3 from a
4 where a.object_id in (select object_id from b)) h
5 on (c.object_id = h.object_id)
6 when matched then
7 update set c.object_name = h.object_name;
616851 行已合并。
已用时间: 00: 00: 12.51
SQL> alter system flush buffer_cache;
系统已更改。
已用时间: 00: 00: 00.00
SQL> declare
2 maxrows number default 100000;
3 row_id_table dbms_sql.urowid_table;
4 --currcount_table dbms_sql.number_Table;
5 object_name_table dbms_sql.varchar2_Table;
6 cursor cur_b is
7 SELECT /*+ index(a) use_hash(a,b) index(b) */
8 a.object_name, b.ROWID ROW_ID
9 FROM A, B
10 WHERE A.object_id = B.object_id
11 ORDER BY B.ROWID; ------有ORDER BY ROWID
12 v_counter number;
13 begin
14 v_counter := 0;
15 open cur_b;
16 loop
17 EXIT WHEN cur_b%NOTFOUND;
18 FETCH cur_b bulk collect
19 into object_name_table, row_id_table limit maxrows;
20 forall i in 1 .. row_id_table.count
21 update b
22 set object_name = object_name_table(i)
23 where rowid = row_id_table(i);
24 commit;
25 end loop;
26 end;
27 /
PL/SQL 过程已成功完成。
已用时间: 00: 00: 31.71
SQL> alter system flush buffer_cache;
系统已更改。
已用时间: 00: 00: 01.87
SQL> declare
2 maxrows number default 100000;
3 row_id_table dbms_sql.urowid_table;
4 --currcount_table dbms_sql.number_Table;
5 object_name_table dbms_sql.varchar2_Table;
6 cursor cur_b is
7 SELECT /*+ index(a) use_hash(a,b) index(b) */
8 a.object_name, b.ROWID ROW_ID
9 FROM A, B
10 WHERE A.object_id = B.object_id;
11 v_counter number;
12 begin
13 v_counter := 0;
14 open cur_b;
15 loop
16 EXIT WHEN cur_b%NOTFOUND;
17 FETCH cur_b bulk collect
18 into object_name_table, row_id_table limit maxrows;
19 forall i in 1 .. row_id_table.count
20 update b
21 set object_name = object_name_table(i)
22 where rowid = row_id_table(i);
23 commit;
24 end loop;
25 end;
26 /
PL/SQL 过程已成功完成。
已用时间: 00: 01: 25.64
MERGE只需要13秒,ORDER BY ROWID 的PL/SQL 需要32秒,而没ORDER BY ROWID 的PL/SQL 需要1分26秒
如果buffer cache不够大(不能容纳下A,B),不order by rowid 要花1分25秒,order by rowid只花了32秒
可见,ORDER BY ROWID 在BUFFER CACHE不够大的情况下,对于速度的提升是非常明显的,因为buffer cache不够大,block可能经常被page out。
order by rowid 会连续更新临近的block,这样就确保读入的block尽可能的不被page out。
为什么Merge 比 用ROWID 去更新快呢?因为MERGE可以多块读,做MERGE的时候设置参数db_file_multiblock_read_count=128
根据ROWID去更新,只能一次读一个block
---------------------BUFFER CACHE 足够大,多次执行,取运行最快的时间---------------------------------------
SQL> alter system set db_keep_cache_size=150m;
系统已更改。
SQL> alter table a storage(buffer_pool keep);
表已更改。
SQL> alter table b storage(buffer_pool keep);
表已更改。
SQL> select /*+ full(a) */ count(*) from a;
COUNT(*)
----------
50526
已用时间: 00: 00: 00.16
SQL> select /*+ full(b) */ count(*) from b;
COUNT(*)
----------
616864
已用时间: 00: 00: 01.08
SQL> SELECT o.OWNER,o.object_type,o.OBJECT_NAME, COUNT(*) NUMBER_OF_BLOCKS
2 FROM DBA_OBJECTS o, V$BH bh
3 WHERE o.DATA_OBJECT_ID = bh.OBJD
4 AND o.owner='SCOTT'
5 GROUP BY o.owner,o.object_type, o.OBJECT_NAME
6 ORDER BY COUNT(*)desc ,2 ;
OWNER OBJECT_TYPE OBJECT_NAME NUMBER_OF_BLOCKS
------------------------------ ------------------- ------------------------------ ----------------
SCOTT TABLE B 8467
SCOTT INDEX IDX_B 1394
SCOTT TABLE A 695
SCOTT INDEX IDX_A 288
SQL> declare
2 maxrows number default 100000;
3 row_id_table dbms_sql.urowid_table;
4 --currcount_table dbms_sql.number_Table;
5 object_name_table dbms_sql.varchar2_Table;
6 cursor cur_b is
7 SELECT /*+ index(a) use_hash(a,b) index(b) */
8 a.object_name, b.ROWID ROW_ID
9 FROM A, B
10 WHERE A.object_id = B.object_id
11 ORDER BY B.ROWID;
12 v_counter number;
13 begin
14 v_counter := 0;
15 open cur_b;
16 loop
17 EXIT WHEN cur_b%NOTFOUND;
18 FETCH cur_b bulk collect
19 into object_name_table, row_id_table limit maxrows;
20 forall i in 1 .. row_id_table.count
21 update b
22 set object_name = object_name_table(i)
23 where rowid = row_id_table(i);
24 commit;
25 end loop;
26 end;
27 /
PL/SQL 过程已成功完成。
已用时间: 00: 00: 11.83
SQL> declare
2 maxrows number default 100000;
3 row_id_table dbms_sql.urowid_table;
4 --currcount_table dbms_sql.number_Table;
5 object_name_table dbms_sql.varchar2_Table;
6 cursor cur_b is
7 SELECT /*+ index(a) use_hash(a,b) index(b) */
8 a.object_name, b.ROWID ROW_ID
9 FROM A, B
10 WHERE A.object_id = B.object_id;
11 v_counter number;
12 begin
13 v_counter := 0;
14 open cur_b;
15 loop
16 EXIT WHEN cur_b%NOTFOUND;
17 FETCH cur_b bulk collect
18 into object_name_table, row_id_table limit maxrows;
19 forall i in 1 .. row_id_table.count
20 update b
21 set object_name = object_name_table(i)
22 where rowid = row_id_table(i);
23 commit;
24 end loop;
25 end;
26 /
PL/SQL 过程已成功完成。
已用时间: 00: 00: 09.71
SQL> merge into b c
2 using (select a.object_name, a.object_id
3 from a
4 where a.object_id in (select object_id from b)) h
5 on (c.object_id = h.object_id)
6 when matched then
7 update set c.object_name = h.object_name;
616851 行已合并。
已用时间: 00: 00: 08.54
ORDER BY ROWID 的PL/SQL 用了11秒,没有ORDER BY ROWID的PL/SQL用了9秒,而Merge最快,只花了8秒多。
(反复测试,以最快时间为准,添加了3个logfile group 每组500Mb,减少logfile对测试的影响)。
由此可见,如果buffer cache够大,不order by rowid 反比order by rowid更快(因为少了排序)
总结:
要非常快 更新 用哪个???
merge into (加hint) + 并行
alter table 要更新的表 nologging
merge into 要么是用来实现功能,要么是用来进行UPDATE 优化。。只能用于UPDATE