[20180226]exp buffer RECORDLENGTH.txt

[20180226]exp buffer RECORDLENGTH.txt

--//虽然已经很少使用exp导致,如果加入direct=y参数,设置RECORDLENGTH参数能加快数据导出.
--//做一些简单探究:
--//以前测试链接:[20171105]exp imp buffer参数解析.txt 2=>http://blog.itpub.net/267265/viewspace-2146870/
--//另外按照文档介绍使用直接路径导出以及导入,参数RECORDLENGTH才有用.
--//另外也顺便探究buffer参数.

Note:

The BUFFER parameter applies only to conventional path Export. It has no effect on a direct path Export. For direct path
Exports, use the RECORDLENGTH parameter to specify the size of the buffer that Export uses for writing to the export
file.

1.环境:
SCOTT@book> @ &r/ver1
PORT_STRING                    VERSION        BANNER
------------------------------ -------------- --------------------------------------------------------------------------------
x86_64/Linux 2.4.xx            11.2.0.4.0     Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

SCOTT@book> show parameter filesystemio_options
NAME                 TYPE   VALUE
-------------------- ------ -----
filesystemio_options string NONE

--//主要目的不使用异步IO,跟踪信息目前还不会看,读懂.

create table t(x number, x2 varchar2(2000),x3 varchar2(1000))  SEGMENT CREATION IMMEDIATE;
insert into t select level, rpad(' ', 100, ' '),rpad('a',100,'a') from dual connect by level <= 1e6;
commit ;
exec sys.dbms_stats.gather_table_stats ( OwnName => 'SCOTT',TabName => 't',Estimate_Percent => NULL,Method_Opt => 'FOR ALL COLUMNS SIZE 1 ',Cascade => True ,No_Invalidate => false);

SCOTT@book> select bytes/1024/1024 from dba_segments where owner=user and segment_name='T';
BYTES/1024/1024
---------------
            232
2.测试:
--//先测试不使用RECORDLENGTH ,direct=y.
$strace -f -o /tmp/exp1.trace exp scott/book file=t.dmp tables=t direct=y
$strace -f -o /tmp/exp2.trace exp scott/book file=t.dmp tables=t direct=y RECORDLENGTH=65535

--//对比:
$ grep 'pread(256' /tmp/exp1.trace | wc
    240    1682   31242
$ grep 'pread(256' /tmp/exp2.trace | wc
    241    1690   31356

--//可以发现读取记录调用次数一样.

$ grep 'write(9' /tmp/exp1.trace | wc
  51468  363523 4364551
$ grep 'write(9' /tmp/exp2.trace | wc
  29040  190891 2606066

$ grep 'write(9' /tmp/exp2.trace | head
13278 write(9, "NTP0 13278\n", 11)      = 11
13278 write(9, "\0 \0\0\2\0\0\0\1:\f\1 \0\20\0\1\0\0\0\0 AA\0\0\0\0\0\0\0\0", 32 <unfinished ...>
13278 write(9, "\0\213\0\0\6\0\0\0\0\0\336\255\276\357\0\201\0\0\0\0\0\4\0\0\4\0\3\0\0\0\0\0"..., 139) = 139
13278 write(9, "\0\332\0\0\6\0\0\0\0\0\1\6\0x86_64/Linux 2.4.xx"..., 218) = 218
13278 write(9, "\0\32\0\0\6\0\0\0\0\0\2\200\0\0\0<<<\200\0\0\0\0\0\0\16", 26) = 26
13278 write(9, "\1\206\0\0\6\0\0\0\0\0\10\3\0\f\0\0\0\fAUTH_SESSKEY`\0"..., 390) = 390
13278 write(9, "\4\210\0\0\6\0\0\0\0\0\10\31\0\23\0\0\0\23AUTH_VERSION_S"..., 1160) = 1160
13278 write(9, "\0\34\0\0\6\0\0\0\0\0\10j\0\0\0\1\0\0\0\0\0\t\1\0\0\0\3\0", 28) = 28
13278 write(9, "\0\26\0\0\6\0\0\0\0\0\10\3\0\0\0\t\1\0\0\0\4\0", 22) = 22
13278 write(9, "\0\222\0\0\6\0\0\0\0\0\4\1\0\0\0\5\0\1\0\0\0\0\0\0\0\0\0\0\3\0\0\0"..., 146) = 146
$ grep 'write(9' /tmp/exp1.trace | head
13255 write(9, "NTP0 13255\n", 11)      = 11
13255 write(9, "\0 \0\0\2\0\0\0\1:\f\1 \0\20\0\1\0\0\0\0 AA\0\0\0\0\0\0\0\0", 32 <unfinished ...>
13255 write(9, "\0\213\0\0\6\0\0\0\0\0\336\255\276\357\0\201\0\0\0\0\0\4\0\0\4\0\3\0\0\0\0\0"..., 139) = 139
13255 write(9, "\0\332\0\0\6\0\0\0\0\0\1\6\0x86_64/Linux 2.4.xx"..., 218) = 218
13255 write(9, "\0\32\0\0\6\0\0\0\0\0\2\200\0\0\0<<<\200\0\0\0\0\0\0\16", 26) = 26
13255 write(9, "\1\206\0\0\6\0\0\0\0\0\10\3\0\f\0\0\0\fAUTH_SESSKEY`\0"..., 390) = 390
13255 write(9, "\4\207\0\0\6\0\0\0\0\0\10\31\0\23\0\0\0\23AUTH_VERSION_S"..., 1159) = 1159
13255 write(9, "\0\34\0\0\6\0\0\0\0\0\10P\0\0\0\3\0\0\0\0\0\t\1\0\0\0\3\0", 28) = 28
13255 write(9, "\0\26\0\0\6\0\0\0\0\0\10\3\0\0\0\t\1\0\0\0\4\0", 22) = 22
13255 write(9, "\0\222\0\0\6\0\0\0\0\0\4\1\0\0\0\5\0\1\0\0\0\0\0\0\0\0\0\0\3\0\35\0"..., 146) = 146

--//可以发现写入文件描述9,开始基本一样.差异在中间:
$ grep 'write(9' /tmp/exp1.trace | less
...
13255 write(9, "\37\333\0\0\6\0\0\0\0\0\10\0 \0\0                 "..., 8155) = 8155
13255 write(9, "\0J\0\0\6\0\0\0\0\0                      "..., 74 <unfinished ...>
13255 write(9, "\37\333\0\0\6\0\0\0\0\0\10\0 \0\0aaaaaaaaaaaaaaaaa"..., 8155) = 8155
13255 write(9, "\0J\0\0\6\0\0\0\0\0aaaaaaaaaaaaaaaaaaaaaa"..., 74 <unfinished ...>
13255 write(9, "\37\333\0\0\6\0\0\0\0\0\10\0 \0\0                 "..., 8155) = 8155
13255 write(9, "\0J\0\0\6\0\0\0\0\0                      "..., 74 <unfinished ...>
13255 write(9, "\37\333\0\0\6\0\0\0\0\0\10\0 \0\0                 "..., 8155) = 8155

--//direct=y,缺省RECORDLENGTH=8192,中间有写入仅仅74字节的情况.

$ grep 'write(9' /tmp/exp2.trace | less
..
13278 write(9, "\37\333\0\0\6\0\0\0\0\0\10\230\375\0\0\3\0\302\2&d\0          "..., 8155) = 8155
13278 write(9, "\37\333\0\0\6\0\0\0\0\0aaaaaa\2\0\301\7d\0          "..., 8155 <unfinished ...>
13278 write(9, "\37\333\0\0\6\0\0\0\0\0                      "..., 8155 <unfinished ...>
13278 write(9, "\37\333\0\0\6\0\0\0\0\0                      "..., 8155 <unfinished ...>
13278 write(9, "\37\333\0\0\6\0\0\0\0\0                      "..., 8155 <unfinished ...>
13278 write(9, "\37\333\0\0\6\0\0\0\0\0                      "..., 8155 <unfinished ...>
13278 write(9, "\37\333\0\0\6\0\0\0\0\0                      "..., 8155 <unfinished ...>
13278 write(9, "\36\374\0\0\6\0\0\0\0\0                      "..., 7932 <unfinished ...>

13278 write(9, "\37\333\0\0\6\0\0\0\0\0\10\377\377\0\0                 "..., 8155) = 8155
13278 write(9, "\37\333\0\0\6\0\0\0\0\0                      "..., 8155 <unfinished ...>
13278 write(9, "\37\333\0\0\6\0\0\0\0\0                      "..., 8155 <unfinished ...>
13278 write(9, "\37\333\0\0\6\0\0\0\0\0\0\302\3<d\0                "..., 8155 <unfinished ...>
13278 write(9, "\37\333\0\0\6\0\0\0\0\0aaaaa\3\0\302\5Ed\0          "..., 8155 <unfinished ...>
13278 write(9, "\37\333\0\0\6\0\0\0\0\0aaaaaaaaaa\3\0\302\6\10d\0     "..., 8155 <unfinished ...>
13278 write(9, "\37\333\0\0\6\0\0\0\0\0aaaaaaaaaaaaaaaa\3\0\302\0071d"..., 8155 <unfinished ...>
13278 write(9, "\37\333\0\0\6\0\0\0\0\0aaaaaaaaaaaaaaaaaaaaaa"..., 8155 <unfinished ...>
13278 write(9, "\1\222\0\0\6\0\0\0\0\0aaaaaaaaaaaaaaaaaaaaaa"..., 402 <unfinished ...>

--//8155*7+7932 = 65017 在直接路径读取方式下.每次读取几乎都是8155,一定程度减少write调用次数.

$ grep 'read(8' /tmp/exp1.trace | wc
  51469  205891 1647256
$ grep 'read(8' /tmp/exp2.trace | wc
  29041  116232  930375

--//同样通过管道read的调用次数也与前面对应.read次数也对应增加.仅仅多1次.

$ grep 'write(6' /tmp/exp1.trace | wc
  51267  339810 3501967
$ grep 'write(6' /tmp/exp2.trace | wc
   6412   42503  444485

$ grep 'write(6' /tmp/exp1.trace | less
13254 write(6, "\3\3TD\nEXPORT:V11.02.00\nDSCOTT\nRTA"..., 8192) = 8192
13254 write(6, "d\0\0\0\0`\1$\17\5\v\f\3\f\f\5\4\5\r\6\t\7\10\5\5\5\5\5\17\5\5\5"..., 4096) = 4096
13254 write(6, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 4096) = 4096
13254 write(6, "                                "..., 4096) = 4096
13254 write(6, "aaaaaaaaa\2\0\301\30d\0                 "..., 4096) = 4096
13254 write(6, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 4096) = 4096
13254 write(6, "                                "..., 4096) = 4096
13254 write(6, "                                "..., 4096) = 4096
13254 write(6, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 4096) = 4096
13254 write(6, "                                "..., 4096) = 4096

$ grep 'write(6' /tmp/exp2.trace | less
13277 write(6, "\3\3TD\nEXPORT:V11.02.00\nDSCOTT\nRTA"..., 61440) = 61440
13277 write(6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096
13277 write(6, "\0\0\0\0`\1$\17\5\v\f\3\f\f\5\4\5\r\6\t\7\10\5\5\5\5\5\17\5\5\5\5"..., 61440) = 61440
13277 write(6, "\0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 4096) = 4096
13277 write(6, "                                "..., 61440) = 61440
13277 write(6, "                                "..., 4096) = 4096
13277 write(6, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 61440) = 61440

--//对比可以发现设置RECORDLENGTH=65535,加大每次写入的字节数,不过开始总是4096,然后61440,
--//4096+61440 = 65536,我估计RECORDLENGTH=65535是从0开始记数的.这样设置大的RECORDLENGTH=65535减少写入调用.
--//而缺省不设置RECORDLENGTH,应该8192.

$ grep 'write(7' /tmp/exp1.trace | wc
  25838  180765 3269275

$ grep 'write(7' /tmp/exp2.trace | wc
   3410   20478  443296

$ grep 'read(6' /tmp/exp1.trace | grep "^13255" |wc
  25838  103355  826900

$ grep 'read(6' /tmp/exp2.trace | grep "^13278" |wc
   3410   13640  109120

--//注意另外一个进程也会出现"read(6"的情况,必须加入开头进程号的过滤.
--//这里文件描述7,6是用来2个进程之间通讯的(我的理解不知道是否正确,^_^).如果你看前面

$ grep 'write(9' /tmp/exp1.trace | less
...
13255 write(9, "\37\333\0\0\6\0\0\0\0\0\10\0 \0\0                 "..., 8155) = 8155
13255 write(9, "\0J\0\0\6\0\0\0\0\0                      "..., 74 <unfinished ...>
--//我的理解以上2行等于写缓存满,写出后,主进程通过文件描述7写信息,通知子进程读取然可以继续读数据写入到文件描述9.
13255 write(9, "\37\333\0\0\6\0\0\0\0\0\10\0 \0\0aaaaaaaaaaaaaaaaa"..., 8155) = 8155
13255 write(9, "\0J\0\0\6\0\0\0\0\0aaaaaaaaaaaaaaaaaaaaaa"..., 74 <unfinished ...>
13255 write(9, "\37\333\0\0\6\0\0\0\0\0\10\0 \0\0                 "..., 8155) = 8155
13255 write(9, "\0J\0\0\6\0\0\0\0\0                      "..., 74 <unfinished ...>
13255 write(9, "\37\333\0\0\6\0\0\0\0\0\10\0 \0\0                 "..., 8155) = 8155

$ grep 'write(9' /tmp/exp1.trace | rev | cut -f1 -d"=" |  grep -v dehsinifnu|wc
  25933   25933  155045
$ grep 'write(9' /tmp/exp2.trace | rev | cut -f1 -d"=" |  grep -v dehsinifnu|wc
   3480    3480   20578

$ grep 'write(9' /tmp/exp1.trace | rev | cut -f1 -d"=" |  grep  "^5518"|wc
  25593   25593  153558
$ grep 'write(9' /tmp/exp2.trace | rev | cut -f1 -d"=" |  grep  "^5518"|wc
   3257    3257   19542
  
--//可以看到这样的结果与上面write 7 的数量很接近.总之可以看出设置direct=y RECORDLENGTH=65535,可以减少open,write调用.
--//加快导出速度.

3.测试:
--//测试加入buffer的情况.
$ strace -f -o /tmp/exp3.trace exp scott/book file=t.dmp tables=t direct=y RECORDLENGTH=65535 buffer=10485760

$ grep 'pread(256' /tmp/exp2.trace | wc
    241    1690   31356
$ grep 'pread(256' /tmp/exp3.trace | wc
    240    1682   31242
--//可以发现读取记录调用次数一样.

$ grep 'write(9' /tmp/exp2.trace | wc
  29040  190891 2606066
$ grep 'write(9' /tmp/exp3.trace | wc
  29040  190884 2606153
--//可以发现写入调用次数一样.

$ grep 'write(6' /tmp/exp2.trace | wc
   6412   42503  444485
$ grep 'write(6' /tmp/exp3.trace | wc
   6412   42498  444515
--//可以发现读取调用次数一样.

$ grep 'write(7' /tmp/exp2.trace | wc
   3410   20478  443296
$ grep 'write(7' /tmp/exp3.trace | wc
   3410   20478  443642

$ grep 'read(6' /tmp/exp2.trace | grep "^13278" |wc
   3410   13640  109120
$ grep 'read(6' /tmp/exp3.trace | grep "^14045" |wc
   3409   13639  109151

--//基本一致.

$ grep 'write(9' /tmp/exp2.trace | rev | cut -f1 -d"=" |  grep -v dehsinifnu|wc
   3480    3480   20578
$ grep 'write(9' /tmp/exp3.trace | rev | cut -f1 -d"=" |  grep -v dehsinifnu|wc
   3496    3496   20679

$ grep 'write(9' /tmp/exp2.trace | rev | cut -f1 -d"=" |  grep  "^5518"|wc
   3257    3257   19542
$ grep 'write(9' /tmp/exp3.trace | rev | cut -f1 -d"=" |  grep  "^5518"|wc
   3279    3279   19674
--//基本接近.说明buffer=10485760对于直接路径导出基本无用.
--//或者讲设置diect=y的情况下buffer设置无用,影响性能的是RECORDLENGTH.

$ time exp scott/book file=t.dmp tables=t  direct=y RECORDLENGTH=65535
real    0m2.072s
user    0m0.132s
sys     0m1.185s

$ time exp scott/book file=t.dmp tables=t buffer=10485760 direct=y RECORDLENGTH=65535
real    0m2.135s
user    0m0.139s
sys     0m1.158s

--//2者很接近.

$ time exp scott/book file=t.dmp tables=t  direct=y
real    0m3.424s
user    0m0.358s
sys     0m1.424s

$ time exp scott/book file=t.dmp tables=t  buffer=10485760
real    0m1.866s
user    0m1.046s
sys     0m0.636s
--//时候使用buffer参数还快一点点.

4.测试使用buffer的情况:
$strace -f -o /tmp/exp2.trace exp scott/book file=t.dmp tables=t direct=y RECORDLENGTH=65535
$strace -f -o /tmp/exp4.trace exp scott/book file=t.dmp tables=t  buffer=10485760

$ grep 'pread(256' /tmp/exp2.trace | wc
    241    1690   31356
$ grep 'pread(256' /tmp/exp4.trace | wc
      0       0       0
$ grep 'pread' /tmp/exp4.trace | wc
      0       0       0

--//使用缓存参数,根本不调用pread.如果你看共享池,可以知道使用buffer参数会执行如下语句.

SCOTT@book> select sql_id,executions,sql_text from v$sql where sql_id='5v855bth711dw';
SQL_ID        EXECUTIONS SQL_TEXT
------------- ---------- --------------------------------------------------------------------------------
5v855bth711dw          1 SELECT /*+NESTED_TABLE_GET_REFS+*/ "SCOTT"."T".* FROM "SCOTT"."T"

--//找到这样的语句,查询sql_text包含NESTED_TABLE_GET_REFS字符串就可以找到.如果使用直接路径读.

$ exp scott/book file=t.dmp tables=t direct=y RECORDLENGTH=65535

SCOTT@book> select sql_id,executions,sql_text from v$sql where sql_id='5v855bth711dw';
SQL_ID        EXECUTIONS SQL_TEXT
------------- ---------- --------------------------------------------------------------------------------
5v855bth711dw          1 SELECT /*+NESTED_TABLE_GET_REFS+*/ "SCOTT"."T".* FROM "SCOTT"."T"

--//你可以发现执行次数并没有增加,这也是直接路径读的特点,直接读取数数据块,绕过了数据缓存.

SCOTT@book> select object_id,data_object_id from dba_objects where owner=user and object_name='T';
OBJECT_ID DATA_OBJECT_ID
---------- --------------
     90385          90385

SCOTT@book> select count(*) from v$bh where objd=90385 and status!='free';
  COUNT(*)
----------
     29696

SCOTT@book> select 29696*8192/1024/1024 from dual ;
29696*8192/1024/1024
--------------------
                 232
--//是因为我的测试环境已经缓存了表T.

SCOTT@book> alter system flush buffer_cache;
System altered.

$ time exp scott/book file=t.dmp tables=t  buffer=10485760
real    0m2.177s
user    0m1.223s
sys     0m0.706s

--//这样基本接近了.
--//限于篇幅,不再展开,总之使用direct=y recordlength=65536 buffer=10485760导出.
--//加快导出速度,为什么要使用buffer,因为如果表lob类型,不支持diect导出,
--//另外11g的一些特性,比如增加字段
--//alter table t add ( c number default 10 not null);这样的情况不能使用direct导出.
--//如果对某一个已经存在数据的表进行了新增了非空+default字段之后,实际上11g因为避免把所有block都修改一遍,所
--//以并没有真正的update底层数据,而是直接修改了数据字典。这样的好处显而易见,alter 表非常快,不会长时间持有library cache
--//lock。执行sql查询这个新字段的时候,对于老的数据sql引擎会自动从数据字典里面把default读出来,对于新的数据就直接读取磁盘上
--//的数据,但是当exp导出的时候,若是采用direct=y,因为跳过sql层,所以直接读取了block,所以老数据的block里面因为没有这个字段
--//当然最终被处理成null插入新表,所以就出现了上述的问题。那么这个问题解决的办法也很简单,就是采用常规形式导出,避免使用
--//direct=y,另外oracle 在10g之后就推荐使用expdp+impdp,这套新工具也能避免这个问题。
--//参考连接=>http://blog.itpub.net/267265/viewspace-2145141/  [20170918]exp 直接路径导出.txt

--//测试例子:
create table t ( a number);
insert into t values(1);
insert into t values(2);
insert into t values(3);
commit;
alter table t add ( c number default 10 not null);

$ exp scott/book file=t.dmp tables=t direct=y RECORDLENGTH=65535

SCOTT@book> alter table t add ( c number default 10 not null);
Table altered.

SCOTT@book> alter table t rename to t1;
Table altered.

$ imp scott/book tables=T file=t.dmp buffer=1048576

Import: Release 11.2.0.4.0 - Production on Mon Feb 26 16:52:37 2018

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.


Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

Export file created by EXPORT:V11.02.00 via direct path
import done in ZHS16GBK character set and AL16UTF16 NCHAR character set
. importing SCOTT's objects into SCOTT
. importing SCOTT's objects into SCOTT
. . importing table                            "T"
IMP-00019: row rejected due to ORACLE error 1400
IMP-00003: ORACLE error 1400 encountered
ORA-01400: cannot insert NULL into ("SCOTT"."T"."C")
Column : 1
Column :
IMP-00019: row rejected due to ORACLE error 1400
IMP-00003: ORACLE error 1400 encountered
ORA-01400: cannot insert NULL into ("SCOTT"."T"."C")
Column : 2
Column :
IMP-00019: row rejected due to ORACLE error 1400
IMP-00003: ORACLE error 1400 encountered
ORA-01400: cannot insert NULL into ("SCOTT"."T"."C")
Column : 3
Column :           0 rows imported
Import terminated successfully with warnings.

SCOTT@book> select * from t;
no rows selected

--//如果要使用direct要检查sys.ecol$;表.看看是否这样定义的表.

SCOTT@book> column BINARYDEFVAL format a10
SCOTT@book> select * from sys.ecol$;
   TABOBJ#     COLNUM BINARYDEFV
---------- ---------- ----------
     90387          2 C10B

SCOTT@book> select object_id,data_object_id,owner,object_name from dba_objects where DATA_OBJECT_ID=90387;
OBJECT_ID DATA_OBJECT_ID OWNER  OBJECT_NAME
---------- -------------- ------ --------------------
     90387          90387 SCOTT  T1

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/267265/viewspace-2151284/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/267265/viewspace-2151284/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值