Tips: AUL License, DBA Tools

用DataCopy进行Oracle数据同步

Posted by anysql on 2010-03-16

    DataCopy(下载)并不一定是指从源端取得数据, 然后INSERT到目标端, 插入只是一个默认操作而已, 其实在目标端还可以做UPDATE或DELETE操作. 对于INSERT可以使用Direct Path Load的方式, 速度可以比得上CTAS, 其他的操作方式, 则只能实现Array DML了. 在日常的DBA工作中, 还是会有一些数据同步的需求的, 这时DataCopy应当可以减轻你的工作量.

    在DataCopy中增加了两个命令行选项, 以支持不同的操作方式.

* sync    = sync mode (INSERT,UPDATE,DELETE,UPDINS,INSUPD,DELINS).
* unique  = primary key or unique key columns of target table.

    除INSERT操作外(SYNC选项的默认值), UPDATE/DELETE操作都需要指定目标端表的主键列, 以用在WHERE条件中. UPDATE操作会根据指定的主键列去更新非主键列的值(SYNC=UPDATE), 而DELETE操作则直接在目标端根据主键列删除记录(SYNC=DELETE).

datacopy user1=... user2=... table1=emp table2=emp_sync sync=delete unique=empno
datacopy user1=... user2=... table1=emp table2=emp_sync sync=update unique=empno

    根据前面的三种基本操作还可以延伸出来额外的三种操作, 在目标端用PL/SQL代码来实现, 第一种是UPDATE-INSERT方式, 在目标端先进行UPDATE, 如果更新0条记录, 则进行INSERT. 这种方式适合于以UPDATE为主的数据同步.

datacopy user1=... user2=... table1=emp table2=emp_sync sync=updins unique=empno

    第二种是INSERT-UPDATE方式, 在目标端先进行INSERT, 如果主键冲突, 则进行UPDATE. 这种方式适合于以INSERT为主的数据同步.

datacopy user1=... user2=... table1=emp table2=emp_sync sync=insupd unique=empno

    第三种是DELETE-INSERT方式, 在目标端先进行DELETE, 再进行INSERT操作. 这种方式的执行成本会比较高, 但逻辑简单.

datacopy user1=... user2=... table1=emp table2=emp_sync sync=delins unique=empno

    后面的三种方式, 如果要用PL/SQL来实现Array接口, 代码还是有一点复杂的, 如果要实现动态SQL的处理, 估计更复杂. 并且大量的循环, 用外部C写的程会更有效率.

学习OCI之DataCopy程序

Posted by anysql on 2010-03-15

    周末继续看了看OCI接口的资料, 着重于以前没有搞懂的LONG/LOB类型处理接口, 写了一个DataCopy程序来作为学习的结果. DataCopy可以在两个Oracle库之间以比较快的速度拷贝数据, 这个速度至少要比EXP/IMP来迁移数据来得快, 并且支持最大100MB的LONG/LONG RAW/CLOB/BLOB值, 一般情况下够用了吧.

    没有说明文档, 只有命令行帮助.

DataCopy: Fast Oracle Data Copy (Demo Version), Release 2.0.1
(c) Copyright Lou Fangxin (AnySQL.net) 2010, all rights reserved.

Usage: datacopy keyword=value [,keyword=value,...]

Valid Keywords:
  user1  = username/password@tnsname for source database.
  user2  = username/password@tnsname for target database.
  table  = table name for both source and target.
  tables  = table name list for both source and target.
  table1  = source table name to query data from.
  table2  = target table name to insert data into.
  query1  = select SQL for source database.
  query2  = insert SQL for target database.
* wait    = wait time in microsecond after each array.
  read    = set DB_FILE_MULTIBLOCK_READ_COUNT at session level
  sort    = set SORT_AREA_SIZE at session level (UNIT:MB)
  hash    = set HASH_AREA_SIZE at session level (UNIT:MB)
  serial  = set _serial_direct_read to TRUE at session level
  array  = array fetch size
  rows    = print log information for every given rows.
  long    = maximum size for long, long raw, CLOB, BLOB columns.
* crypt  = encrypt the connection info only, no data copy (YES/NO).
  parfile = read command option from parameter file
* direct  = direct mode (YES/NO).
* nolog  = no archive log for direct mode (YES/NO).
* parallel= allow parallel load for direct mode (YES/NO).
* sync    = sync mode (INSERT,UPDATE,DELETE,UPDINS,INSUPD,DELINS).
* unique  = primary key or unique key columns of target table.
  log    = log file name for screen messages.

Notes:
  datacopy user1=scott/tiger user2=scott/tiger table=emp
  datacopy user1=scott/tiger user2=scott/tiger table=emp direct=yes
  datacopy user1=scott/tiger user2=scott/tiger table1=emp table2=emp_his

    数据拷贝中, 目标端数据库并不一定是INSERT操作, 也可以是UPDATE或DELETE, 或一段PL/SQL代码, 默认情况下是INSERT而已. 并且也只是实现了OCI的Array操作接口, 在真实情况下有什么实用价值, 就让各自去延伸了.

SQLULDR2从标准输入读取SQL

Posted by anysql on 2010-03-10

    从今天开始, SQLULDR2可以从标准输入设备接受复杂的SQL语句了. 如下所示, SQL是人工输入的, 而最后一行的反斜杆用来表示输入结束.

D:\>sqluldr2 scott/tiger file=- sql=-
select
*
from tab
/
DBOBJECTS,TABLE,
BLOB,TABLE,
SPACE_DAILY,TABLE,
SQLULDR2_LOG,TABLE,
TRADE_MONTHLY_SUMMARY,TABLE,
TRADE_DATA,TABLE,

    这个可以省去创建SQL文件的步骤, 更重要的是在Linux的Shell或Perl脚本中调用SQLULDR2, 并传入复杂的SQL时, 也不需要创建SQL文件了, 而且很容易使用Shell或Perl中的变量, 进行替换生成动态的SQL. 例如, 我们经常会见到如下脚本.

sqlplus -s "/ as sysdba" << EOF
select
*
from tab;
exit
EOF

    现在SQLULDR2也可以这样用了, 在Linux的Shell或Perl脚本中同样使用.

sqluldr2 sys file=- sql=- << EOF
select
*
from tab
EOF

    使用这个功能, 可以使嵌入SQLULDR2的批脚本更具有通用性, 方便移值到不同的平台.

简化SQLULDR2的命令行选项设置

Posted by anysql on 2010-03-06

    看到Kamus对SQLULDR2的留言后, 破有感触. 人们应当比较关注, 他们想要的功能用起来方便是否, 关键并不在于功能的多少. 而SQLULDR2的众多的命令行选项, 也确实有些让人发晕, 包括我自已.

    为了方便大多数人使用, 简化了SQLULDR2的命令行帮助, 简化到如下所示.

SQL*UnLoader: Fast Oracle Text Unloader (GZIP), Release 3.0.1
(@) Copyright Lou Fangxin (AnySQL.net) 2004 - 2010, all rights reserved.

Usage: SQLULDR2 keyword=value [,keyword=value,...]

Valid Keywords:
  user    = username/password@tnsname
  sql    = SQL file name
  query  = select statement
  field  = separator string between fields
  record  = separator string between records
  rows    = print progress for every given rows (default, 1000000)
  file    = output file name(default: uldrdata.txt)
  log    = log file name, prefix with + to append mode
  fast    = auto tuning the session level parameters(YES)
  text    = output type (MYSQL, CSV, MYSQLINS, ORACLEINS, FORM, SEARCH).
  parfile = read command option from parameter file

  for field and record, you can use '0x' to specify hex character code,
  \r=0x0d \n=0x0a |=0x7c ,=0x2c, \t=0x09, :=0x3a, #=0x23, "=0x22 '=0x27

    对于专家而言, 可以用如下方式得到以前全部的命令行选项.

sqluldr2 help=yes

    通过引入一个TEXT选项, 来针对不同格式的导出进行相关选项的设置, 不仅方便了大家使用, 也可以对SQLULDR2的功能有一个很直接的了解, 例如SQLULDR2可以导出数据给MySQL用, 或导出成Excel可以打开的标准CSV文件, 或是生成MySQL和ORACLE上的INSERT语句, 也可以按列显示记录, 或为一些特殊的搜索程序生成数据源.

    再次感谢Kamus的好建议, 今年是支付宝的用户体验年, 应当从用户角度进行反思.

为DataReport增加条件过滤功能

Posted by anysql on 2010-03-04

    为了查询出保存在员工表(SCOTT.EMP)中, 每个部门工资最高的三个人, 如果是Oracle数据库, 大家可以使用Windows分组汇总函数来轻松地实现, 如下所示.

SELECT * FROM (
SELECT DEPTNO, EMPNO, ENAME, SAL,
  RANK() OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) RNK
FROM EMP ) WHERE RNK <= 3

    但如果员工表存放在MySQL数据库, 或其他数据库, 如SQLLite中, 要实现同样的功能, 就比较复杂了, 至少我现在都还不会. 但利用DataReport以前开发的功能, 及刚增加的条件过滤功能, 就可以轻松实现这个需求.

webchart.query_1=select deptno, empno, ename, sal from emp
webchart.express_1=rank|x|rnk::sal|deptno
webchart.filter_1=3.5-x|rank
webchart.sort_1=deptno,rank
webchart.group_1=1

    如果Filter中的公司算出来的值小于0, 那么这条记录就会被删除, 在这个例子中, 如果排名这一列的值大于3, 这个公式算出来的值就为负数, 所以只保留了前三名, 达到了我们的业务要求. 页面输出如下所示的表格:

deptnoempnoenamesalrank
107839KING5000.01
7782CLARK2450.02
7934MILLER1300.03
207788SSCOTT3000.01
7902FORD3000.02
7566JONESS2975.03
307698BLAKE2850.01
7499ALLEN1600.02
7844TURNER1500.03

    将这些处理放在应用服务器端实现, 不仅让SQL变得通用, 如果访问频率极高, 还可以减轻数据库端的压力.


Copyright © 2007 AnySQL.net. All rights reserved.