部分代码如下:
OracleConnection conn=new OracleConnection(“Data Source=db;User id=user;Password=pass”);
conn.Open();
OracleCommand cmd=new OracleCommand();
cmd.Connection=conn;
OracleTransaction trans=conn.BeginTransaction();
cmd.Transaction=trans;
Stopwatch stp=new Stopwatch();
cmd.CommandText=”insert into dbk_test values(to_date(’2012-06-05 10:00:00′,’yyyy-mm-dd hh24:mi:ss’),’1234567890′,’987654321′,’This is a test message’)”;
for(int i=0;i<20000;++i)
{
cmd.ExecuteNonQuery();
if(i%1000==0)
trans.Commit();
}
trans.Commit();
conn.Close();
stp.Stop();
Console.writeLine(“Time Elapsed:”+stp.ElapsedMilliseconds+”ms”);
C#程序运行在Windows Server 2008 32位上,机器为Xeon E552O * 2,2.27Ghz,共16核内存12GB。Oracle 安装在Redhat AS4U4,cpu为AMD Opterron 275 * 2 ,2.2GHz,共4核心,内存16GB,oracle 10g。
测试结果为33秒左右,每秒插入不到700条,之后也采用了绑定变量及调用存储过程等方法,插入速度也没有多大提高。
于是想到了用ODP.net,在网上查到说ODAC的版本必须与安装的oracle对应,虽然这个要求感觉不太灵活,因为实际的使用环境可能与开发环境不一致,到时还要更换ODAC的版本,且ODAC在官网上并不是能对应上所有的Oracle版本。在网上看到使用ODP.net插入速度可以达到数万条每秒,但我多次尝试时,都在运行时出现问题,根本无法运行成功。于是便放弃了。Oracle与MS的东西兼容性不强,或者说是Oracle本身向下兼容的能力弱,真是令人抓狂。
多方查找后发现了OCI这个东西,于是想到了使用封装了OCI的OCCI,这样眼前突然一亮。之后的思路就很清淅了,先用c++做一个dll,里面的函数是对OCCI的进行一步封装,再用c#调用这个dll就可以了。下面就是实现的具体过程了。
首先遇到的第一个问题是如何封装OCCI,由于我使用的开发环境是VS2010,在网上查找了一番,找到了这篇http://oradim.blogspot.com/2009/07/getting-started-with-occi-windows.html,这里面的开发环境是VS2008,可以仿照在vs2010中实现。
我们需要以去Oracle官网下载以下一些组件:
OCCI
Instant Client Package Basic
Instant Client Package SDK
去这个地址http://www.oracle.com/technetwork/database/occidownloads-083553.html下载OCCI,通过这个表格可以看到VS2010之前的IDE都需要安装客户端之后可以进行开发,而对于VS2010并不需要安装Oracle 客户端,只需下载一个组件即可,这里我下载的是vs2010 32bit的11.2.3.0版本。由于Oracle 客户端是向下兼容的,因此使用11版本的客户端可以连接我的10g数据库。接着支这里http://www.oracle.com/technetwork/topics/winsoft-085727.html下载Instant client package basic及intstant client package SDK,需要注意的是这两个组件的版本号也必须为11.2.3.0。
下面的仿照着上面给出的那篇BLOG做了,将instant_basic解压到D盘,形成了如下的目录结构,d:\instantclient_11_2,下面会有文件及VC8,VC9文件夹,将这两个文件夹删去。将instant_sdk解压,其会在d:\instantclient_11_2目录下生成一个sdk目录,即形如d:\instantclient_11_2\sdk。如果不是的话可以手动调整一下。
将上面下载的occivc10_11203解压到d:\temp,在D:\instantclient_11_2\sdk\lib\msvc目录下创建VC10目录,形成的目录结构如d:\instantclient_11_1\sdk\lib\msvc\vc10,在d:\instantclient_11_2下新建目录VC10。将d:\instantclient_11_2下的oraocci11.dll及oraocci11.sym删除,因为其与VS2010不兼容。从d:\temp中找到oraocci11.lib及oraocci11d.lib,将这两个文件复制到d:\instantclient_11_2\sdk\lib\msvc\vc10,在从d:\temp找到oraocci11.dll及oraocci11d.dll,将这两个文件复制到d:\instantclient_11_2\VC10,将D:\instantclient_11_2\sdk\lib\msvc下的oraocci11.lib删去。最后的工作是设置环境变量,将d:\instantclient_11_2\vc10及d:\instantclient_11_2加入到path内容的最前面。
先创建一个工程,选择c++中空工程OracleConnection,生成可执行的程序的格式为dll。然后在solution explorer中右OracleConnection,选择Properties->Configuration Properties–>vc++ Directories,在Include Directories中加上occi.h所在的位置d:\instantclient_11_2\sdk\include,在Library Directories中加上lib文件的目录d:\instantclient_11_2\sdk\lib\msvc\vc10。上面这两个设置完成后还要到Linker下的Input中,在Additional Dependencies的最后面加上oraocci11d.lib(如果是release模式下请用oraocci11.lib)。至此所有配置及安装工作完成了,可以封装OCCI的dll了。
使用C#调用封装好的dll,测试了下插入的执行速度,达到了近4万条每秒,相比于ADO.NET,速度有质的飞跃了。
封装及测试的代码在以下的链接下载