㈠ 直接路径加载和buffer cache
       
       直接路径插入的数据不经过buffer cache,从PGA直接把数据格式化成Oracle块
       然后由普通的Oracle Server Process进程把数据块写入数据文件
       因为不经过buffer cache,所以不需要DBWn介入
       
       假如有表a,现要将a中的数据插入表b,在普通的插入下,需先将a的数据块I/O到buffer cache
       在buffer cache中从a的块中读出行,插进b的块中
       此时,b的块就都变成了脏块,再等待DBWn把他们flush到数据文件
       因此,普通插入后,a表和b表的块都会在buffer cache中出现
       
       而直接路径插入,将a表的数据块I/O到buffer cache,读出行,直接写进b表所在的数据文件
       插入完成后,除了表头块外,b表的数据块并未在buffer cache中出现过

测试:

  1. hr@ORCL> create table a (id number,name varchar2(10));
  2. Table created.
  3. hr@ORCL> create table b (id number,name varchar2(10));
  4. Table created.
  5. hr@ORCL> insert into a values(1,'aa');
  6. 1 row created.
  7. hr@ORCL> insert into a values(2,'bb');
  8. 1 row created.
  9. hr@ORCL> insert into a values(3,'cc');
  10. 1 row created.
  11. hr@ORCL> insert into a values(4,'dd');
  12. 1 row created.
  13. hr@ORCL> commit;
  14. Commit complete.
  15. hr@ORCL> select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid) from a;
  16. DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
  17. ------------------------------------ ------------------------------------
  18. 4                                  508
  19. 4                                  508
  20. 4                                  508
  21. 4                                  508
  22. --现在a表有4行,占用块508,而目前b表还木有数据
  23. --将buffer cache清空
  24. hr@ORCL> alter system flush buffer_cache;
  25. System altered.
  26. --先用直接路径插入,从a表向b表插入数据
  27. hr@ORCL> insert /*+ append */ into b select * from a;
  28. 4 rows created.
  29. hr@ORCL> commit;
  30. Commit complete.
  31. --使用v$bh查看buffer cache中的块
  32. hr@ORCL> select file#,block# from v$bh where objd=(select data_object_id from user_objects where object_name='A');
  33. FILE#     BLOCK#
  34. ---------- ----------
  35. 4        508     ←←当前包含数据的块
  36. 4        508     ←←当前包含数据的块
  37. 4        511
  38. 4        511
  39. 4        506
  40. 4        509
  41. 4        509
  42. 4        512
  43. 4        512
  44. 4        507
  45. 4        507
  46. 4        510
  47. 4        510
  48. 4        505
  49. 14 rows selected.
  50. --这是因为对a表进行全表扫,a表中低高水位点下所有的块都被读进buffer cache,这其中当然也包括508了
  51. hr@ORCL> select file#,block# from v$bh where objd=(select data_object_id from user_objects where object_name='B');
  52. FILE#     BLOCK#
  53. ---------- ----------
  54. 4       2571
  55. 4       2569
  56. 4       2570
  57. hr@ORCL> select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid) from b;
  58. DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
  59. ------------------------------------ ------------------------------------
  60. 4                                 2572
  61. 4                                 2572
  62. 4                                 2572
  63. 4                                 2572
  64. --上面两个查询可以看到,b表中的数据占用地2572块,但是,直接路径插入后,2572并没有被调入buffer cache
  65. --buffer cache中只有2569 2570 2571
  66. --其中2571是段头块(select header_file,header_block from dba_segments where segment_name='B')
  67. --2570 2569则是L1 L2这两个位图块
  68. --接下来使用普通插入
  69. hr@ORCL> alter system flush buffer_cache;
  70. System altered.
  71. hr@ORCL> insert into b select * from a;
  72. 4 rows created.
  73. hr@ORCL> commit;
  74. Commit complete.
  75. hr@ORCL> select file#,block# from v$bh where objd=(select data_object_id from user_objects where object_name='B');
  76. FILE#     BLOCK#
  77. ---------- ----------
  78. 4       2571
  79. 4       2574
  80. 4       2569
  81. 4       2575
  82. 4       2570
  83. 4       2570
  84. 4       2573
  85. 4       2576  ←←本次普通插入的数据所在的块
  86. 8 rows selected.
  87. hr@ORCL> select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid) from b;
  88. DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
  89. ------------------------------------ ------------------------------------
  90. 4                                 2572
  91. 4                                 2572
  92. 4                                 2572
  93. 4                                 2572
  94. 4                                 2576
  95. 4                                 2576
  96. 4                                 2576
  97. 4                                 2576
  98. 8 rows selected.

从上面的实验可以证明,普通插入,要先将数据块传进buffer cache
       这是Oracle通常修改数据的方式,不对数据文件直接进行修改,而是在内存中完成修改,再由日志提供保护
       对于小量的修改,这是种可取的方法,但对于大数据交易,直接路径将可以提供更好的性能
       
       还有就是,直接路径加载是在高水位之上完成的插入动作,因此无论高水位下有多少空闲块都会被忽略,段空间将会随之增大

㈡ 直接路径加载和undo
     
       差别比较明显的是undo(直接路径几乎没有undo),俩者redo差不多(普通插入稍微多点redo,因为Oracle需要redo来保护undo)
       直接路径用HWM回滚,普通插入用undo回滚

  1. --再次向b表使用直接路径插入
  2. hr@ORCL> insert /*+ append */ into b select id+4,name from a;
  3. 4 rows created.
  4. --查看事务信息
  5. hr@ORCL> select xidusn,xidslot,xidsqn,ubafil,ubablk,ubasqn from v$transaction;
  6. XIDUSN    XIDSLOT     XIDSQN     UBAFIL     UBABLK     UBASQN
  7. ---------- ---------- ---------- ---------- ---------- ----------
  8. 10         23        314          0          0          0
  9. --因为当前只有一个事务,因此选择v$transaction视图时没有加条件
  10. --从上面的显示结果可以看到,ubafil ubablk为0,也就是,此事务没有对应的回滚块
  11. --只有在回滚段头的事务表中占用了一行而已

那么直接路径插入是如何提供回滚的呢?观察b表的HWM的变化,就可以解答这个问题

  1. --查找b表的HWM
  2. hr@ORCL> select header_file,header_block from dba_segments where segment_name='B';
  3. HEADER_FILE HEADER_BLOCK
  4. ----------- ------------
  5. 4         2571
  6. hr@ORCL> alter session set tracefile_identifier='hr_2571';
  7. Session altered.
  8. hr@ORCL> alter system dump datafile 4 block 2571;
  9. System altered.
  10. --trc文件摘入如下:
  11. Extent Control Header
  12. -----------------------------------------------------------------
  13. Extent Header:: spare1: 0      spare2: 0      #extents: 2      #blocks: 16
  14. last map  0x00000000  #maps: 0      offset: 2716
  15. Highwater::  0x01000a11  ext#: 0      blk#: 8      ext size: 8
  16. #blocks in seg. hdr's freelists: 0
  17. #blocks below: 8
  18. mapblk  0x00000000  offset: 0
  19. Unlocked
  20. --------------------------------------------------------
  21. Low HighWater Mark :
  22. Highwater::  0x01000a11  ext#: 0      blk#: 8      ext size: 8
  23. --高水位点是4号文件2577号块
  24. --提交后查看直接路径插入到哪个块中
  25. hr@ORCL> select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid) from b where id>=8;
  26. DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
  27. ------------------------------------ ------------------------------------
  28. 4                                 2577
  29. --通过上面的查询,本次直接路径插入,数据被存进2577号块,而提交的HWM正是2577
  30. |--------------|--------|--------|----------
  31. |数据块 ...... |2575|2576|2577|2578|...
  32. |--------------|--------|--------|----------
  33. 此处是高水位点,直接路径插入从此块开始分配空间
  34. --直接路径插入,是在高水位点之上分配临时段,将数据插入时进入此临时段
  35. --在提交后将高水位点提升至临时段之上
  36. --现在已经提交,再来看高水位点的信息
  37. hr@ORCL> alter system dump datafile 4 block 2571;
  38. System altered.
  39. --trc文件摘入如下:
  40. Extent Control Header
  41. -----------------------------------------------------------------
  42. Extent Header:: spare1: 0      spare2: 0      #extents: 2      #blocks: 16
  43. last map  0x00000000  #maps: 0      offset: 2716
  44. Highwater::  0x01000a12  ext#: 1      blk#: 1      ext size: 8
  45. #blocks in seg. hdr's freelists: 0
  46. #blocks below: 9
  47. mapblk  0x00000000  offset: 1
  48. Unlocked
  49. --------------------------------------------------------
  50. Low HighWater Mark :
  51. Highwater::  0x01000a12  ext#: 1      blk#: 1      ext size: 8
  52. --第一次dump是Highwater::  0x01000a11,而现在是 Highwater::  0x01000a12
  53. --高水位点升至2578块,如下图
  54. |--------------|--------|--------|--------|-----
  55. |数据块 ......  |2575  |2576|2577|2578|
  56. |--------------|--------|--------|--------|-----
  57. 高水位点上升至此处
  58. --再试一次直接路径插入回滚时的情况
  59. --先猜想一下,此次插入应该插入到2578,如果提交的话,就提升高水位点到2579,如果回滚的话,保持高水位点不变
  60. hr@ORCL> insert /*+ append */ into b select id+4,name from a;
  61. 4 rows created.
  62. hr@ORCL> commit;
  63. Commit complete.
  64. --trc摘入如下:
  65. Extent Control Header
  66. -----------------------------------------------------------------
  67. Extent Header:: spare1: 0      spare2: 0      #extents: 2      #blocks: 16
  68. last map  0x00000000  #maps: 0      offset: 2716
  69. Highwater::  0x01000a13  ext#: 1      blk#: 2      ext size: 8
  70. #blocks in seg. hdr's freelists: 0
  71. #blocks below: 10
  72. mapblk  0x00000000  offset: 1
  73. Disk Lock:: Locked by xid:  0x0006.012.0000018d
  74. --------------------------------------------------------
  75. Low HighWater Mark :
  76. Highwater::  0x01000a13  ext#: 1      blk#: 2      ext size: 8
  77. --高水位点变为 0x01000a13 ,也就是2579块
  78. --接下来是回滚,回滚则将保持高水位点不变,也就是在2579块
  79. hr@ORCL> insert /*+ append */ into b select id+12,name from a;
  80. 4 rows created.
  81. hr@ORCL> rollback;
  82. Rollback complete.
  83. hr@ORCL> alter system dump datafile 4 block 2571;
  84. System altered.
  85. --trc文件摘入如下:
  86. Extent Control Header
  87. -----------------------------------------------------------------
  88. Extent Header:: spare1: 0      spare2: 0      #extents: 2      #blocks: 16
  89. last map  0x00000000  #maps: 0      offset: 2716
  90. Highwater::  0x01000a13  ext#: 1      blk#: 2      ext size: 8
  91. #blocks in seg. hdr's freelists: 0
  92. #blocks below: 10
  93. mapblk  0x00000000  offset: 1
  94. Unlocked
  95. --------------------------------------------------------
  96. Low HighWater Mark :
  97. Highwater::  0x01000a13  ext#: 1      blk#: 2      ext size: 8
  98. --0x01000a13,也就是2579块,rollback,高水位点没有变化

在执行直接路径加载的过程中,高水位并没有真正提高,只有在事务提交后才会完成这个动作,在所有维护工作完成之后表才可以被访问
       所以,在提交之前如果想查询这张表是不被允许的,同理可知对表的增删改以及merge操作也是不被允许的

㈢ 直接路径加载与index
       
       直接路径插入时,不产生表块的回滚信息,而是依赖高水位点实现回滚
       但是,如果表有索引,将会产生索引的回滚信息,而且索引的块会被读进buffer cache 
       测试:

  1. --为b表创建一个索引
  2. hr@ORCL> create index idx_b on b (id);
  3. Index created.
  4. hr@ORCL> select file#,block# from v$bh where objd=(select data_object_id from user_objects where object_name='IDX_B');
  5. FILE#     BLOCK#
  6. ---------- ----------
  7. 4       2587   ←← 段头块
  8. 4       2585   ←← L1块
  9. 4       2588   ←← 第一个索引数据块
  10. 4       2586   ←← L2块
  11. --重启数据库,清空buffer cache
  12. hr@ORCL> select file#,block# from v$bh where objd=(select data_object_id from user_objects where object_name='IDX_B');
  13. no rows selected
  14. hr@ORCL> insert /*+ append */ into b select * from a;
  15. 4 rows created.
  16. hr@ORCL> select file#,block# from v$bh where objd=(select data_object_id from user_objects where object_name='IDX_B');
  17. FILE#     BLOCK#
  18. ---------- ----------
  19. 4       2588
  20. --直接路径插入时,索引块仍然会被调入buffer cache
  21. hr@ORCL> select xidusn,xidslot,xidsqn,ubafil,ubablk,ubasqn from v$transaction;
  22. XIDUSN    XIDSLOT     XIDSQN     UBAFIL     UBABLK     UBASQN
  23. ---------- ---------- ---------- ---------- ---------- ----------
  24. 6         41        399          2       1456        261
  25. --并且,对于索引块的修改,将会产生回滚信息,回滚信息保存在回滚块1456处
  26. --因此,索引并不会"直接路径插入"
  27. --因此,插入的索引数据,应该是在高水位点下:
  28. hr@ORCL>  select header_file,header_block from dba_segments where segment_name='IDX_B';
  29. HEADER_FILE HEADER_BLOCK
  30. ----------- ------------
  31. 4         2587
  32. hr@ORCL> alter system dump datafile 4 block 2587;
  33. System altered.
  34. --trc文件摘入如下:
  35. Extent Control Header
  36. -----------------------------------------------------------------
  37. Extent Header:: spare1: 0      spare2: 0      #extents: 1      #blocks: 8
  38. last map  0x00000000  #maps: 0      offset: 2716
  39. Highwater::  0x01000a1d  ext#: 0      blk#: 4      ext size: 8
  40. #blocks in seg. hdr's freelists: 0
  41. #blocks below: 1
  42. mapblk  0x00000000  offset: 0
  43. Unlocked
  44. --------------------------------------------------------
  45. Low HighWater Mark :
  46. Highwater::  0x01000a1d  ext#: 0      blk#: 4      ext size: 8
  47. --高水位点在2589块处,插入的索引数据在2588处,在高水位点下

Oracle官方文档建议,如果使用直接路径插入,向表中传送大量数据,可先将表上的索引删掉,插入结束后,再重新建立索引

㈣ 直接路径加载和一些限制
       
       使用直接路径加载方法时需要注意的地方如下:
       1)直接路径加载方法不是所有插入方式都支持的,最常见的带有value子句的insert语句就不支持
       2)该技术最常用在insert into ... select ...结构的插入语句中
       3)在使用直接路径加载技术插入数据直到事务提交,其他的增、删、改、查和merge操作是被禁止的
       4)因为是直接路径加载,所以高水位以下的空闲数据库块将不被使用,可能会因此导致数据段无限扩张
       5)当被操作的表上存在insert触发器、外键、IOT、表使用到了聚簇技术以及表中包含LOB字段时
            直接路径加载技术是无效的,此时将会自动的转变为常规插入

㈤ 小结
          
          使用直接路径加载技术之所以能提高性能是因为,该方法可以保证在加载数据的过程中最大限度的减少回滚数据的生成
          expdp/impdp不支持直接路径,而sqlldr支持(由参数direct=true指定,并且同时指定parallel=true,速度将会更快)
          如果我们在权衡利弊成本之后能最大化该方法,提高加载速度是必然的!

本文转自:http://blog.csdn.net/dba_waterbin/article/details/8607016

Oracle直接路径加载--append的深度解析的更多相关文章

  1. Oracle sqlldr数据加载

    1 sqlldr 传统路径:sqlldr会利用sql插入为我们加载数据 直接路径加载:sqlldr不适用sql,直接格式化数据块,绕开undo,避开redo,最快的方法就是并行直接路径加载 sqlld ...

  2. HttpRunner3源码阅读:4. loader项目路径加载,用例文件转换、方法字典生成

    loader.py 这个文件中主要是对yaml,json用例加载转换成用例处理, 预置函数加载成方法字典,路径加载等 可用资料 [importlib]. https://docs.python.org ...

  3. [Django] html 前端页面jQuery、图片等路径加载问题

    严格的说这个话题应该属于一个html前端路径加载问题.为了实现一个局部更新页面的功能,简单了解了一下Ajax.Ajax是一个为了实现浏览器和服务器异步通信功能的模块.严格来说不是一个新的语言,只是JS ...

  4. Android图片加载框架最全解析(八),带你全面了解Glide 4的用法

    本篇将是我们这个Glide系列的最后一篇文章. 其实在写这个系列第一篇文章的时候,Glide就推出4.0.0的RC版了.那个时候因为我一直研究的都是Glide 3.7.0版本,再加上RC版本还不太稳定 ...

  5. Android图片加载框架最全解析(六),探究Glide的自定义模块功能

    不知不觉中,我们的Glide系列教程已经到了第六篇了,距离第一篇Glide的基本用法发布已经过去了半年的时间.在这半年中,我们通过用法讲解和源码分析配合学习的方式,将Glide的方方面面都研究了个遍, ...

  6. Android图片加载框架最全解析(四),玩转Glide的回调与监听

    大家好,今天我们继续学习Glide. 在上一篇文章当中,我带着大家一起深入探究了Glide的缓存机制,我们不光掌握了Glide缓存的使用方法,还通过源码分析对缓存的工作原理进行了了解.虽说上篇文章和本 ...

  7. Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程

    在本系列的上一篇文章中,我们学习了Glide的基本用法,体验了这个图片加载框架的强大功能,以及它非常简便的API.还没有看过上一篇文章的朋友,建议先去阅读 Android图片加载框架最全解析(一),G ...

  8. 未知的生成错误 因为没有预加载,所以无法解析程序集 GalaSoft.MvvmLight

    使用wpf开发时,在ViewModel中引用了DevExpress注册的GalaSoft.MvvmLight命名空间,使用其ViewModelBase,在View界面中绑定事件时出现错误: 错误 13 ...

  9. Android图片加载框架最全解析(七),实现带进度的Glide图片加载功能

    我们的Glide系列文章终于要进入收尾篇了.从我开始写这个系列的第一篇文章时,我就知道这会是一个很长的系列,只是没有想到竟然会写这么久. 在前面的六篇文章中,我们对Glide的方方面面都进行了学习,包 ...

随机推荐

  1. schema get_ddl

    select dbms_metadata.get_ddl('INDEX','INDEX_CC_TAXID','CACS9DBSIT1') from dual; select dbms_metadata ...

  2. Apache CXF实战之四 构建RESTful Web Service

    Apache CXF实战之一 Hello World Web Service Apache CXF实战之二 集成Sping与Web容器 Apache CXF实战之三 传输Java对象 这篇文章介绍一下 ...

  3. Codeforces E. Bash Plays with Functions(积性函数DP)

    链接 codeforces 题解 结论:\(f_0(n)=2^{n的质因子个数}\)= 根据性质可知\(f_0()\)是一个积性函数 对于\(f_{r+1}()\)化一下式子 对于 \[f_{r+1} ...

  4. springboot + 拦截器 + 注解 实现自定义权限验证

    springboot + 拦截器 + 注解 实现自定义权限验证最近用到一种前端模板技术:jtwig,在权限控制上没有用springSecurity.因此用拦截器和注解结合实现了权限控制. 1.1 定义 ...

  5. IO模型同步与异步阻塞与非阻塞的区别

    同步异步的区别 关注点:同步和异步关注的是消息通信机制 同步:所谓同步,就是在发出一个*调用*时,在没有得到结果之前,该*调用*就不返回.但是一旦调用返回,就得到返回值了.换句话说,就是由*调用者*主 ...

  6. SQL SERVER Update from 使用陷阱

    原文:SQL SERVER Update from 使用陷阱 update A set from A left join B on 此方法常用来使用根据一个表更新另一个表的数据,来进行数据同步更新.若 ...

  7. A system tap script to detect UDP beacons

    https://gist.github.com/jbradley89/178bbf3944786c494bd78f3df16a5472

  8. jdk7 cpocurrent ForJoinPool

    19. 使用 ForkJoinPool 进行分叉和合并 ForkJoinPool 在 Java 7 中被引入.它和 ExecutorService 很相似,除了一点不同.ForkJoinPool 让我 ...

  9. 【maven】maven的web项目打包报错:No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK

    打包过程中报错如下: No compiler is provided in this environment. Perhaps you are running on a JRE rather than ...

  10. react热加载失败

    react热加载失败 原因:路径名字大小写错误, 不是全部加载失败,有的时候可以用,有的时候不可以 热加载插件:webpack-dev-server