当前位置:  数据库>oracle

C#+“外部表”实现Oracle数据快速插入

    来源: 互联网  发布时间:2017-04-04

    本文导语:    Oracle是大型数据库,可以用于存储海量数据。对于数据的来源,也有多种途径,其中有一部分是随着业务的发展不断添加进来的,也有在业务系统初始化的时候,批量导入进来的。对于不断添加这个过程,不在此进行描述,...

   Oracle是大型数据库,可以用于存储海量数据。对于数据的来源,也有多种途径,其中有一部分是随着业务的发展不断添加进来的,也有在业务系统初始化的时候,批量导入进来的。对于不断添加这个过程,不在此进行描述,只对批量导入做一个简单的说明。

    以下涉及到的开发环境为:VS2008 + Oracle9i

    对于批量导入有多种方式,各种方式的操作方式及效率也各不相同,下面我们来做一个简单的测试。

    一.准备工作

    1.先要在Oracle中建一个测试表供插入使用,可以建三个字段,SQL语句请参考:

    create table TEST
    (
    ID VARCHAR2(100),
    NAME VARCHAR2(100),
    DOB DATE
    )




    在上例中,我特意做了一个日期型的字段,因为日期型的字段涉及到一个格式问题,比较复杂,所以特意在此说明。

    2.准备批量数据

   上面已经建好了测试表,下面就要准备一些测试数据准备插入之用,文件的格式如下:

    1~name:1~2009-04-10 10:00:00

    2~name:3~2009-04-10 10:00:00

    3~name:3~2009-04-10 10:00:00

    以上数据全部为测试数据,没有任何实际含义,并且每个字段之间用~来分隔。之所有没有用传统的逗号作分隔符,是考虑字符串中可能会出现这个逗号,以免引起混淆。

    第一次我们先准备50万条记录作测试,以免压力太大系统不能承受,因为我的测试机是一个很老的笔记本,性能非常差劲。

    二.插入方式对比

    上面准备了测试数据,下面就要来把这些数据插入到第一步建的测试表中,对于如何插入,实在是有太多的方式了,我只挑选两种比较极端的情况来做个比较

    1.使用外部程序来处理插入(C#)

    这是一种传统的做法,使用ODBC/OleDB等方式与数据库连接,并使用标准的insert进行插入操作。为了实现这种方式,需要把文本文件每一行读出来,把各个字段拆解开,再拼接成SQL语句,从而实现数据的插入,简单的程序片断如下:

DataAccessor data = new DataAccessor();

string sql = "truncate table test";

data.ExecuteNonQuery(sql);

System.Diagnostics.Debug.WriteLine(System.DateTime.Now.ToString());

System.IO.StreamReader reader = new System.IO.StreamReader("c:\temp\data.txt");

string line = "";

while (line != null)

{

line = reader.ReadLine();

if (line != null)

{

string[] lines = line.Split('~');

sql = "insert into test (id,name,dob) values(" + lines[0]

+ ",'" + lines[1] + "',to_date('" + lines[2]

+ "','yyyy-mm-dd hh24:mi:ss'))";

data.ExecuteNonQuery(sql);

if ((int.Parse(lines[0]) % 10000) == 0)

{

System.Diagnostics.Debug.WriteLine(lines[0]);

}

}

}

System.Diagnostics.Debug.WriteLine(System.DateTime.Now.ToString());

    从上述代码,可以很清楚的看出读文件及拆解插入的过程,不再过多的说明。

    这种方式的特点是插入的中间过程可以控制,可以加上人机交互,可以知道插入的状态,并且可以随时停止插入的过程,但是缺点是速度比较慢。

    2.使用外部表的方式来插入

    所谓外部表,是用于区分Oracle的普通表的一种格式。普通的表都是建立在数据库的内部,数据存储也是在Oracle的自身数据文件中,而外部表,则是类似一个指针,直接指向外部物理文件,比如上面测试用的data.txt,可以直接映射成一个外部表。

    使用外部表的方式我感觉在原理上与第一种方式没有太大的本质区别,只是所有这些中间处理的过程全部由Oracle自己来完成,它很清楚怎么做性能会比较好,所以这种方式是不错的选择。

    外部平面文件本身只是存储数据,并不能对字段等信息进行自描述,所以还需要在引用的时候,强行指定文本文件的格式,这样就能“自圆其说”了。

    在创建外部表之前,还要先声明一点:Oracle是一个独立的数据库系统,它的所有操作全是在它自己的进程中完成,因此如果需要引用外部操作系统的文件,必须通知它,再加上一些权限上的考虑,还需要做一些特别的配置才可以实现上述的功能,主要的动作包括以下几步:

    I. 增加Oracle对文件指定目录的权限

    Oracle数据库能访问哪些操作系统的目录,必须提前指定好,否则是没有权限的,这个指定需要修改Oracle的一个初始参数,比如我把平面文件放在了c:temp的目录下,就要这样修改:

    alter system set utl_file_dir='c:temp' scope=spfile;

    这里有一点需要记住,修改这个参数后,数据库必须重启才能生效。

    II. 创建一个内部目录

    重起数据库后,就可以在Oracle内建一个目录的引用,这个引用将直接指向外部的目录,如:

   create directory temp as ‘c:temp’;

    为什么要这样做呢,其实也就是包装一下,因为在程序中不能直接引用操作系统的路径名,这样包装一下后,直接引用temp就可以了。

    经过以上两步的准备工作,正式的建表工作就要开始喽!看看下面的SQL,是不是有点眼晕:

create table zr_user_temp_ext(

USER_ID VARCHAR2(20) ,

USER_ALIAS VARCHAR2(20),

QQ date)

ORGANIZATION EXTERNAL

(

TYPE ORACLE_LOADER

DEFAULT DIRECTORY temp

ACCESS PARAMETERS

(

RECORDS DELIMITED BY NEWLINE

FIELDS TERMINATED BY '~'

MISSING FIELD VALUES ARE NULL

(user_id,user_alias,

qq date "YYYY-MM-DD HH24:MI:SS"

)

)

LOCATION('data.txt')

)

下面我来对上面的SQL中的几个主要部分做个说明:

Ø Create table:

这部分代码与标准的表一样,并且在里面指定字段名等内容,没有特别的地方

Ø ORGANIZATION EXTERNAL

这个子句就表明现在声明的是一个外部表而不是一张普通的表噢

Ø DEFAULT DIRECTORY temp

这个子句指定外部表的文件在哪个目录中取得

Ø RECORDS DELIMITED BY NEWLINE

这个子句说明文本文件中的每一行就是一个记录。但是当数据库服务器的操作系统不同的时候,这个文本文件的换行符也需要特别注意一下,因为在NT系统里,换行采用nr双字节来表示,而在UNIX/LINUX系统下,换行只用一个字节来表示,所以如果是从NT系统生成的文件,传到LINUX进行处理的时候,有可能就会出问题。

Ø FIELDS TERMINATED BY '~'

这个子句用于表示各个字段间用什么来分隔,根据上面文件的格式,可以看出这个子句的含义。

Ø MISSING FIELD VALUES ARE NULL

这个子句说明如果一个记录中某个字段的值没有,则按“空”来处理

qq date "YYYY-MM-DD HH24:MI:SS"

这个子句也比较有用,它用于指定日期型字段的格式码,这个格式码将直接与文件中的格式相对应,这样才能实现数据的正确读取和导入。

Ø LOCATION('data.txt')

这个子句用于指明外部文件的文件名,与目录名拼接在一起,就可以在操作系统中对其进行精确的定位了。

此外,还有很多的参数,我这里都没有写,全部采用了默认值,我也没有太关心过其它参数,能用就行了,呵。

还需要注意一点,这个SQL只检查语法错误,而对于物理文件是否存在,它并不做任何检查,因为此需要大家自己把握好这一点。

好了,到此文件,我们伟大的外部表已经创建完成了,来试一下吧:

select * from test_ext;

如果不出意外,您会看到,平面文件已经用表的形式展现在您的面前了,哈,真是很开心吧。但是到目前为止,虽然我们能以表的形式来展现数据,但是数据实际上还是存储于外部的,还需要把它实际的导入进来才可以。这个导入就更简单了,比如:

insert into test select * from test_ext;

就这么简单,外部表在使用起来和内部表没什么区别。

当然还可以再加上hint功能,让这个插入更加快速。

    三.选择适合自己的方式

    上面只介绍了两种方式,除此之外,还可以用sql loader等其它方式,也可以在存储过程中对文件进行拆解插入,这两种方式我都试验过了,与外部表的性能类似,但是使用更加麻烦,也不便于程序调用,所以我推荐外部表的方式。

    在数据量较小的时候,比如100条记录,几种方式真的没有太大区别,1秒和0.01秒对于客户来说,没有什么实质的差异,但是如果是50万或更多的记录数,就要考虑这个问题了。下面是我的几个测试数据可以供大家参考:

插入方式

50万条

500万条

C#

17分钟

未测试

外部表

4.8秒

48秒

    如果您关心性能,从上表可以很明显找到适合您的导入方案了。

    四.结论

    虽然外部表的方式效率非常高,但是操作复杂也是它的一个弊端,它会给您的应用程序带来很多不必要的麻烦,而且如果应用程序与数据库服务器不在一起,甚至操作系统都不一样,还要增加上传文件的操作,几个步骤之间的协调关系也需要做很多的考虑。

    总之,上述方式是一个不错的方式,仅供大家选择。

天道酬勤不酬怨
李鸣(aicken)原创 转载注明
if ($ != jQuery) { $ = jQuery.noConflict(); } var isLogined = false; var cb_blogId = 50701; var cb_entryId = 1707455; var cb_blogApp = "isline"; var cb_blogUserGuid = "8cf016b0-1cf5-dd11-9e4d-001cf0cd104b"; var cb_entryCreatedDate = '2010/4/8 15:57:00';

    
 
 

您可能感兴趣的文章:

  • vi 中如何实现列插入呢?
  • 在ubuntu环境下实现自动检测usb设备插入,拔除?的程序呢?
  • python插入排序算法的实现代码
  • python 实现插入排序算法
  • 使用存储过程实现循环插入100条记录
  • 在Python3中使用urllib实现http的get和post提交数据操作 iis7站长之家
  • 我想插入一条记录到库中,但有要判断username 是否存在于库中/(插入我以实现)<大家来看看)
  • mysql 选择插入数据(包含不存在列)具体实现
  • MySQL下将一个表的数据插入到另外一个表的实现语句
  • Python实现冒泡,插入,选择排序简单实例
  • SQLServer用存储过程实现插入更新数据示例
  • 使用C#实现在word中插入页眉页脚的方法
  • 插入排序的顺序表实现代码
  • 存储过程配合UpdateDaset方法批量插入Dataset数据实现代码
  • sql server批量插入与更新的实现代码
  • mysql如果数据不存在,则插入新数据,否则更新的实现方法
  • mssql2008 自定义表类型实现(批量插入或者修改)
  • mysql 记录不存在时插入 记录存在则更新的实现方法
  • MYSQL批量插入数据的实现代码第1/3页
  • C语言实现带头结点的链表的创建、查找、插入、删除操作
  • php实现socket实现客户端和服务端数据通信源代码
  • 怎样实现在jsp/servlet中调出数据库的数据,并实现刷新和滚动,分我会再加的
  • 在Python3中使用urllib实现http的get和post提交数据操作
  • qt如何实现:操作键盘实现数据的滚动?
  • 如何实现 coreos 下Docker 与分布式数据库结合
  • 如何用java实现将数据库中的image类型数据导出到文本文件。并导入(高分求救!!)
  • php通过pack和unpack函数实现对二进制数据封装及解析
  • 怎样实现从数据库中下载blob数据到本地硬盘?
  • 数据结构:图(有向图,无向图),在Python中的表示和实现代码示例
  • 我想把csdn的论坛改成一个软件平台,另外增加数据查询功能,聊天功能,不知怎样实现比较好?我想用jbuider 7+SQL server实现,不知如何?
  • linux下用什么办法连接oracle数据库并且读取数据呢?(用c++代码实现时)
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 通过javascript实现DIV居中,兼容各浏览器版本
  • socket实现多文件并发传输,求助多线程实现问题?
  • Python GUI编程:tkinter实现一个窗口并居中代码
  • interface 到底有什么用???实现接口,怎么实现??
  • 通过javascript库JQuery实现页面跳转功能代码
  • 怎么用Jsp实现在页面实现树型结构?
  • sharepoint 2010 使用STSNavigate函数实现文件下载举例
  • windows 下的PortTunnel 在linux下怎么实现?或者相应的已经实现的软件?端口映射
  • flash AS3反射实现(describeType和getDefinitionByName)
  • 网站重定向用C语言实现iptables,ACL实现
  • boost unordered_map和std::list相结合的实现LRU算法
  • 在linux下如何编程实现nslookup命令实现的IP地址和域名互相转换的功能?
  • c#通过委托delegate与Dictionary实现action选择器代码举例
  • 求在freebsd+Squid下实现pc上网的透明代理的实现方法!给出具体配置方法的高分谢!
  • 使用java jdk中的LinkedHashMap实现简单的LRU算法
  • linux下如实现与window下的驱动器实现文件共享??
  • iphone cocos2d 精灵的动画效果(图片,纹理,帧)CCAnimation实现
  • 我想用APPLET实现读取客户端的图片文件,该如何实现?
  • c语言判断某一年是否为闰年的各种实现程序代码
  • PING是用TCP,还是用UDP来实现的?或是采用其它协议实现的?
  • html<pre>标签自动换行实现方法
  • ejb-ql只能 like '?%' 么?我想实现模糊查寻,想实现 like'%?%' 怎么办??


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3