并用各种方法导入示例数据集来计算总体导入时间和导入进程占用金沙js娱乐场官方网站:,示例表结构和数据集

Oracle 数据库的CALLS表中,接受导入数据的表名是 CALLS,示例表结构和数据集,接受导入数据的表名是 CALLS,Oracle.DataAccess.Client

运用上述方法,程序将外部数据提取到内存中的数组里,并执行批量插入操作,保留了表的删除/重建索引操作,总的导入时间下降到
14 秒,而进程占用 CPU
的时间下降到7秒,可见实际导入数据所花费的时间显著下降了 95%。

数据导入的最简单方法就是编写 INSERT
语句,将数据逐条插入数据库。这种方法只适合导入少量数据,如 SQL*Plus
脚本创建某个表的种子数据。该方法的最大缺点就是导入速度缓慢,占用了大量的
CPU
处理时间,不适合大批量数据的导入;而其主要优点就是导入构思简单又有修改完善的弹性,不需要多做其它的准备就可以使用。如果你有很多时间没法打发,又想折磨一下数据库和
CPU,那这种方法正适合你。

组件:Oracle.DataAccess.dll(2.112.1.0)

这种方法的优点是可以加快导入的速度并使索引更加紧凑有效;缺点是缺乏通用性,当你对表增加新的复杂的模式元素时你需要添加代码、修改导入执行程序。另外针对
7*24
在线要求的数据库在线导入操作时,删除表的索引会对在线用户的查询有很大的性能影响,同时也要考虑,主要或唯一的关键约束条件的删除或失效可能会影响到引用它们的外键的使用。

为什么上一种方法占用了较多的 CPU 处理时间,关键是 CALLS
表中已创建了索引,当一条数据插入到表中时,Oracle
需要判别新数据与老数据在索引方面是否有冲突,同时要更新表中的所有索引,重复更新索引会消耗一定的时间。因此提高导入速度的好办法就是在创建表时先不创建索引或者在导入数据之前删除所有索引,在外部文件数据逐条插入到表中后再统一创建表的索引。这样导入速度会提高,同时创建的索引也很紧凑而有效,这一原则同样适用于位图索引。对于主要的和唯一的关键约束(key
constraints),可以使之先暂时失效(disabling)或者删除约束来获得同样的效果,当然这些做法会对已经存在的表的外键约束产生相关的影响,在删除前需要通盘斟酌。

工具:Microsoft Visual Studio Ultimate 2013 + Oracle SQL Developer
1.5.5 + Oracle Database 11g Enterprise Edition 11.2.0.1.0(32位)
+ TNS for 32-bit Windows 11.2.0.1.0

为什么上一种方法占用了较多的 CPU 处理时间,关键是 CALLS
表中已创建了索引,当一条数据插入到表中时,Oracle
需要判别新数据与老数据在索引方面是否有冲突,同时要更新表中的所有索引,重复更新索引会消耗一定的时间。因此提高导入速度的好办法就是在创建表时先不创建索引或者在导入数据之前删除所有索引,在外部文件数据逐条插入到表中后再统一创建表的索引。这样导入速度会提高,同时创建的索引也很紧凑而有效,这一原则同样适用于位图索引。对于主要的和唯一的关键约束(key
constraints),可以使之先暂时失效(disabling)或者删除约束来获得同样的效果,当然这些做法会对已经存在的表的外键约束产生相关的影响,在删除前需要通盘斟酌。

接受导入数据的表名是 CALLS,表结构如下:

 

Name Null? Type Comment———— ——— ————-
—————–CALL_ID NOT NULL NUMBER Primary keyCALL_DATE NOT NULL
DATE Non-unique indexEMP_ID NOT NULL NUMBERCALL_TYPE NOT NULL
VARCHAR2(12)DETAILS VARCHAR2(25)

批量插入,表暂无索引

总结

1、在30+万和60+万数据时,ArrayBind一次性导入和OracleBulkCopy时间相差不是很大,但是ArrayBind方式一般都需要转换数据形式,占用了一些时间,而
OracleBulkCopy 则只需要简单处理一下 DataTable 数据源即可导入;

2、当数据量达到100+万时,ArrayBind
很容易出现内存不足异常,此时只能采用分批次执行导入,根据测试结果可知,次数越少,速度越快;而采用
OracleBulkCopy 方式则很少出现内存不足现象,由此可见 OracleBulkCopy
占用内存比 ArrayBind 方式少;

3、采用 OracleBulkCopy 导入时,先要禁用该表所有触发器,如果该表存在自增
ID 触发器,就比较麻烦了,得先禁用改变的自增 ID
的触发器,然后手动自增设置要导入的数据,最后才可以导入;同时,这种导入方式不可并发,一个时刻只能有一个用户在导入(因为自增ID交由程序处理),此时还需要锁表,防止其他人同时批量导入数据;

82302284384,2003-04-18:13:18:58,5001,投诉,手机三包维修质量82302284385,2003-04-18:13:18:59,3352,咨询,供水热线的号码82302284386,2003-04-18:13:19:01,3142,建议,增设公交线路

这种方法的优点是可以加快导入的速度并使索引更加紧凑有效;缺点是缺乏通用性,当你对表增加新的复杂的模式元素时你需要添加代码、修改导入执行程序。另外针对
7*24
在线要求的数据库在线导入操作时,删除表的索引会对在线用户的查询有很大的性能影响,同时也要考虑,主要或唯一的关键约束条件的删除或失效可能会影响到引用它们的外键的使用。

方式二:OracleBulkCopy

说明:

  1. OracleBulkCopy 采用 direct path 方式导入;

  2. 不支持 transaction,无法 Rollback;

  3. 如果该表存在触发器时,无法使用 OracleBulkCopy(报异常信息 Oracle
    Error: ORA-26086),除非先禁用该表的所有触发器;

  4. 过程中会自动启用 NOT NULL、UNIQUE 和 PRIMARY KEY 三种约束,其中 NOT
    NULL 约束在列数组绑定时验证,任何违反 NOT NULL
    约束条件的行数据都会舍弃;UNIQUE
    约束是在导入完成后重建索引时验证,但是在 bulk copy
    时,允许违反索引约束,并在完成后将索引设置成禁用(UNUSABLE)状态;而且,如果索引一开始状态就是禁用(UNUSABLE)状态时,OracleBulkCopy
    是会报错的。

参考代码如下:

  1 /// <summary>
  2 /// 批量插入数据
  3 /// 该方法需要禁用该表所有触发器,并且插入的数据如果为空,是不会采用默认值
  4 /// </summary>
  5 /// <param name="table">数据表</param>
  6 /// <param name="targetTableName">数据库目标表名</param>
  7 /// <returns></returns>
  8 public bool InsertBulkData(DataTable table, string targetTableName)
  9 {
 10     bool result = false;
 11     string connStr = GetConnectionString();
 12     using (OracleConnection connection = new OracleConnection(connStr))
 13     {
 14         using (OracleBulkCopy bulkCopy = new OracleBulkCopy(connStr, OracleBulkCopyOptions.Default))
 15         {
 16             if (table != null && table.Rows.Count > 0)
 17             {
 18                 bulkCopy.DestinationTableName = targetTableName;
 19                 for (int i = 0; i < table.Columns.Count; i++)
 20                 {
 21                     string col = table.Columns[i].ColumnName;
 22                     bulkCopy.ColumnMappings.Add(col, col);
 23                 }
 24                 connection.Open();
 25                 bulkCopy.WriteToServer(table);
 26                 result = true;
 27             }
 28             bulkCopy.Close();
 29             bulkCopy.Dispose();
 30         }
 31     }
 32 
 33     return result;
 34 }

测试结果:

数据类型:4列NVARCHAR2,2列NUMBER

30+万(7.36M):用时 14:590

60+万(14.6M):用时 28:28

1048576(24.9M):用时 52:971

附加,禁用表的所有外键SQL:

ALTER TABLE table_name DISABLE ALL TRIGGERS

逐条数据插入 INSERT,表暂无索引

在Oracle V6 中 OCI
编程接口加入了数组接口特性。数组操作允许导入程序读取外部文件数据并解析后,向数据库提交SQL语句,批量插入
SQL 语句检索出的数据。Oracle 仅需要执行一次 SQL
语句,然后在内存中批量解析提供的数据。批量导入操作比逐行插入重复操作更有效率,这是因为只需一次解析
SQL
语句,一些数据绑订操作以及程序与数据库之间来回的操作都显著减少,而且数据库对每一条数据的操作都是重复可知的,这给数据库提供了优化执行的可能。其优点是数据导入的总体时间明显减少,特别是进程占用
CPU 的时间。

ODP.NET 版本:ODP.NET for .NET Framework 2.0 或 ODP.NET for .NET
Framework 4