[Oracle] Bulk Insert Data上海时时乐走势图官网

方式三:INSERT INTO xx select...

方式二: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

我们通过SQL脚本来插入数据,常见如下四种方式。

组件:Oracle.DataAccess.dll(2.112.1.0)

create database CarSYS;    
go    
use CarSYS;    
go 
CREATE TABLE Product(
Id UNIQUEIDENTIFIER PRIMARY KEY,
NAME VARCHAR(50) NOT NULL,
Price DECIMAL(18,2) NOT NULL
)

工具: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

方式三:使用TVPs(表值参数)插入数据

从sqlserver 2008起开始支持TVPs。创建缓存表ProductTemp ,执行如下SQL。

CREATE TYPE ProductTemp AS  TABLE(
Id UNIQUEIDENTIFIER PRIMARY KEY,
NAME VARCHAR(50) NOT NULL,
Price DECIMAL(18,2) NOT NULL
)

执行完成之后,会发现在数据库CarSYS下面多了一张缓存表ProductTemp

上海时时乐走势图官网 1

上海时时乐走势图官网 2

可见插入100w条记录共花费了11秒多。

命名空间:Oracle.DataAccess.Client

在C#中通过ADO.NET来实现批量操作存在四种与之对应的方式。

 

本篇,我将来讲解一下在Sqlserver中批量插入数据。

参考资料:

1、ArrayBind

2、ArrayBind

3、Oracle数据导入方法

4、介绍OracleBulkCopy类

5、

方式二:使用SqlBulk

        #region 方式二
        static void InsertTwo()
        {
            Console.WriteLine("使用Bulk插入的实现方式");
            Stopwatch sw = new Stopwatch();
            DataTable dt = GetTableSchema(); 

            using (SqlConnection conn = new SqlConnection(StrConnMsg))
            {
                SqlBulkCopy bulkCopy = new SqlBulkCopy(conn);
                bulkCopy.DestinationTableName = "Product";
                bulkCopy.BatchSize = dt.Rows.Count;
                conn.Open();
                sw.Start();

                for (int i = 0; i < totalRow;i   )
                {
                    DataRow dr = dt.NewRow();
                    dr[0] = Guid.NewGuid();
                    dr[1] = string.Format("商品", i);
                    dr[2] = (decimal)i;
                    dt.Rows.Add(dr);
                }
                    if (dt != null && dt.Rows.Count != 0)
                    {
                        bulkCopy.WriteToServer(dt);
                        sw.Stop();
                    }
                    Console.WriteLine(string.Format("插入{0}条记录共花费{1}毫秒,{2}分钟", totalRow, sw.ElapsedMilliseconds, GetMinute(sw.ElapsedMilliseconds)));
            }
        }
        static DataTable GetTableSchema()
        {
            DataTable dt = new DataTable();
            dt.Columns.AddRange(new DataColumn[] {   
        new DataColumn("Id",typeof(Guid)),  
        new DataColumn("Name",typeof(string)),  
        new DataColumn("Price",typeof(decimal))});
            return dt;
        }
        #endregion

运行结果如下:

上海时时乐走势图官网 3

插入100w条记录才8s多,是不是很溜。

打开Sqlserver Profiler跟踪,会发现执行的是如下语句:

insert bulk Product ([Id] UniqueIdentifier, [NAME] VarChar(50) COLLATE Chinese_PRC_CI_AS, [Price] Decimal(18,2))

方式一:ArrayBind

当插入一条数据时,SQL 语句如下:

INSERT INTO table_name VALUES (:col1, :col2, :col3, :col4, :col5)

  1 public void InsertDataRow(Dictionary<string, object> dataRow)
  2 {
  3     StringBuilder sbCmdText = new StringBuilder();
  4     sbCmdText.AppendFormat("INSERT INTO {0}(", m_TableName);
  5     sbCmdText.Append(string.Join(",", dataRow.Keys.ToArray()));
  6     sbCmdText.Append(") VALUES (");
  7     sbCmdText.Append(":"   string.Join(",:", dataRow.Keys.ToArray()));
  8     sbCmdText.Append(")");
  9 
 10     using (OracleConnection conn = new OracleConnection())
 11     {
 12         using (OracleCommand cmd = conn.CreateCommand())
 13         {
 14             cmd.CommandType = CommandType.Text;
 15             cmd.CommandText = sbCmdText.ToString();
 16             OracleParameter parameter = null;
 17             OracleDbType dbType = OracleDbType.Object;
 18             foreach (string colName in dataRow.Keys)
 19             {
 20                 dbType = GetOracleDbType(dataRow[colName]);
 21                 parameter = new OracleParameter(colName, dbType);
 22                 parameter.Direction = ParameterDirection.Input;
 23                 parameter.OracleDbTypeEx = dbType;
 24                 parameter.Value = dataRow[colName];
 25                 cmd.Parameters.Add(parameter);
 26             }
 27             conn.Open();
 28             int result = cmd.ExecuteNonQuery();
 29         }
 30     }
 31 }

此时,每一个 OracleParameter 的 Value 值都赋予单个字段的 一个具体值,这种也是最为传统的插入数据的方法。

Oracle V6 中 OCI 编程接口加入了数组接口特性。

当采用 ArrayBind 时,OraleParameter 的 Value 值则是赋予单个字段的 一个数组,即多条数据的该字段组合成的一个数组。此时 Oracle 仅需要执行一次 SQL 语句,即可在内存中批量解析并导入数据,减少程序与数据库之间来回的操作,其优点就是数据导入的总体时间明显减少,尤其是进程占用 CPU 的时间。

如果数据源是 DataTable 类型,首先把 DataTable 数据源,转换成 object[][] 类型,然后绑定 OracleParameter 的 Value 值为对应字段的一个 Object[] 数组即可;参考代码如下:

  1 /// <summary>
  2 /// 批量插入大数据量
  3 /// </summary>
  4 /// <param name="columnData">列名-列数据字典</param>
  5 /// <param name="dataCount">数据量</param>
  6 /// <returns>插入数据量</returns>
  7 public int InsertBigData(Dictionary<string, object> columnData, int dataCount)
  8 {
  9     int result = 0;
 10     if (columnData == null || columnData.Count < 1)
 11     {
 12         return result;
 13     }
 14     string[] colHeaders = columnData.Keys.ToArray();
 15     StringBuilder sbCmdText = new StringBuilder();
 16     if (columnData.Count > 0)
 17     {
 18         // 拼接INSERT的SQL语句
 19         sbCmdText.AppendFormat("INSERT INTO {0}(", m_TableName);
 20         sbCmdText.Append(string.Join(",", colHeaders));
 21         sbCmdText.Append(") VALUES (");
 22         sbCmdText.Append(m_ParameterPrefix   string.Join(","   m_ParameterPrefix, colHeaders));
 23         sbCmdText.Append(")");
 24         OracleConnection connection = null;
 25         try
 26         {
 27             connection = new OracleConnection(GetConnectionString());
 28             using (OracleCommand command = connection.CreateCommand())
 29             {
 30                 command.ArrayBindCount = dataCount;
 31                 command.BindByName = true;
 32                 command.CommandType = CommandType.Text;
 33                 command.CommandText = sbCmdText.ToString();
 34                 command.CommandTimeout = 1800;
 35                 OracleParameter parameter;
 36                 OracleDbType dbType = OracleDbType.Object;
 37                 foreach (string colName in colHeaders)
 38                 {
 39                     dbType = GetOracleDbType(columnData[colName]);
 40                     parameter = new OracleParameter(colName, dbType);
 41                     parameter.Direction = ParameterDirection.Input;
 42                     parameter.OracleDbTypeEx = dbType;
 43                     parameter.Value = columnData[colName];
 44                     command.Parameters.Add(parameter);
 45                 }
 46                 connection.Open();
 47                 OracleTransaction trans = connection.BeginTransaction();
 48                 try
 49                 {
 50                     command.Transaction = trans;
 51                     result = command.ExecuteNonQuery();
 52                     trans.Commit();
 53                 }
 54                 catch (Exception ex)
 55                 {
 56                     trans.Rollback();
 57                     throw ex;
 58                 }
 59             }
 60         }
 61         finally
 62         {
 63             if (connection != null)
 64             {
 65                 connection.Close();
 66                 connection.Dispose();
 67             }
 68             GC.Collect();
 69             GC.WaitForFullGCComplete();
 70         }
 71     }
 72     return result;
 73 }

上海时时乐走势图官网 4上海时时乐走势图官网 5

  1 /// <summary>
  2 /// 根据数据类型获取OracleDbType
  3 /// </summary>
  4 /// <param name="value">数据</param>
  5 /// <returns>数据的Oracle类型</returns>
  6 private static OracleDbType GetOracleDbType(object value)
  7 {
  8     OracleDbType dataType = OracleDbType.Object;
  9     if (value is string[])
 10     {
 11         dataType = OracleDbType.Varchar2;
 12     }
 13     else if (value is DateTime[])
 14     {
 15         dataType = OracleDbType.TimeStamp;
 16     }
 17     else if (value is int[] || value is short[])
 18     {
 19         dataType = OracleDbType.Int32;
 20     }
 21     else if (value is long[])
 22     {
 23         dataType = OracleDbType.Int64;
 24     }
 25     else if (value is decimal[] || value is double[] || value is float[])
 26     {
 27         dataType = OracleDbType.Decimal;
 28     }
 29     else if (value is Guid[])
 30     {
 31         dataType = OracleDbType.Varchar2;
 32     }
 33     else if (value is bool[] || value is Boolean[])
 34     {
 35         dataType = OracleDbType.Byte;
 36     }
 37     else if (value is byte[])
 38     {
 39         dataType = OracleDbType.Blob;
 40     }
 41     else if (value is char[])
 42     {
 43         dataType = OracleDbType.Char;
 44     }
 45     return dataType;
 46 }

GetOracleDbType

说明:如果采用分次(每次1万数据)执行 InsertBigData 方法,速度反而比一次性执行 InsertBigData 方法慢,详见下面测试结果;

测试结果:

无索引,数据类型:4列NVARCHAR2,2列NUMBER

30 万(7.36M):一次性导入用时 15:623,每次10000导入用时

60 万(14.6M):一次性导入用时 28:207,每次10000导入用时 1:2:300

100 万(24.9M):一次性导入报如下异常

上海时时乐走势图官网 6

此时实际上从资源监视器上可以得知仍有可用内存,但是仍旧报 OutOfMemoryException,所以猜测应该是一个 bug;

如果每次10000导入用时 2:9:252

如果每次50000导入用时 58:101

附加 InsertBigData 方法使用示例:

上海时时乐走势图官网 7上海时时乐走势图官网 8

  1 // 每10000数据导入一次
  2 Dictionary<string, object> columnsData = new Dictionary<string, object>();
  3 int dataCount = m_SourceDataTable.Rows.Count;
  4 int times = dataCount / 10000   (dataCount % 10000 == 0 ? 0 : 1);
  5 for (int i = 0; i < times; i  )
  6 {
  7     int startIndex = i * 10000;
  8     int endIndex = (i   1) * 10000;
  9     endIndex = endIndex > dataCount ? dataCount : endIndex;
 10     int currDataCount = endIndex - startIndex;
 11     columnsData.Add("COL1", new string[currDataCount]);
 12     columnsData.Add("COL2", new string[currDataCount]);
 13     columnsData.Add("COL3", new decimal[currDataCount]);
 14     columnsData.Add("COL4", new string[currDataCount]);
 15     columnsData.Add("COL5", new decimal[currDataCount]);
 16     columnsData.Add("COL6", new string[currDataCount]);
 17     for (int rowIndex = startIndex; rowIndex < endIndex; rowIndex  )
 18     {
 19         int dicRowIndex = rowIndex - startIndex;// 列数据行索引
 20         foreach (string colName in columnsData.Keys)
 21         {
 22             object cell = m_SourceDataTable.Rows[rowIndex][colName];
 23             string cellStr = (cell   "").TrimEnd(new char[] { '\0', ' ' });
 24             if (colName == "COL3" || colName == "COL5")
 25             {
 26                 decimal value = 0;
 27                 decimal.TryParse(cellStr, out value);
 28                 ((decimal[])columnsData[colName])[dicRowIndex] = value;
 29             }
 30             else
 31             {
 32                 ((string[])columnsData[colName])[dicRowIndex] = cellStr;
 33             }
 34         }
 35     }
 36     m_DAL.InsertBigData(columnsData, currDataCount);
 37 
 38     columnsData.Clear();
 39     GC.Collect();
 40     GC.WaitForFullGCComplete();
 41 }

View Code

方式四:拼接SQL

总结

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

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

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

语法如下:

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

INSERT INTO Product(Id,Name,Price) VALUES
(newid(),'牛栏1段',160)
,(newid(),'牛栏2段',260)
......

方式一:逐条插入

        #region 方式一
        static void InsertOne()
        {
            Console.WriteLine("采用一条一条插入的方式实现");
            Stopwatch sw = new Stopwatch();

            using (SqlConnection conn = new SqlConnection(StrConnMsg)) //using中会自动Open和Close 连接。
            {
                string sql = "INSERT INTO Product(Id,Name,Price) VALUES(newid(),@p,@d)";
                conn.Open();
                for (int i = 0; i < totalRow; i  )
                {
                    using (SqlCommand cmd = new SqlCommand(sql, conn))
                    {
                        cmd.Parameters.AddWithValue("@p", "商品"   i);
                        cmd.Parameters.AddWithValue("@d", i);
                        sw.Start();
                        cmd.ExecuteNonQuery();
                        Console.WriteLine(string.Format("插入一条记录,已耗时{0}毫秒", sw.ElapsedMilliseconds));
                    }
                    if (i == getRow)
                    {
                        sw.Stop();
                        break;
                    }
                }
            }
            Console.WriteLine(string.Format("插入{0}条记录,每{4}条的插入时间是{1}毫秒,预估总得插入时间是{2}毫秒,{3}分钟",
 totalRow, sw.ElapsedMilliseconds, ((sw.ElapsedMilliseconds / getRow) * totalRow), GetMinute((sw.ElapsedMilliseconds / getRow * totalRow)), getRow));
        }
        static int GetMinute(long l)
        {
            return (Int32)l / 60000;
        } 
        #endregion

运行结果如下:

 上海时时乐走势图官网 9

我们会发现插入100w条记录,预计需要50分钟时间,每插入一条记录大概需要3毫秒左右。

方式二:insert bulk

INSERT INTO Product(Id,Name,Price)
 SELECT NEWID(),'牛栏1段',160 
 UNION ALL 
 SELECT NEWID(),'牛栏2段',180
 UNION ALL
...... 
    BULK INSERT [ [ 'database_name'.][ 'owner' ].]{ 'table_name' FROM 'data_file' }       
    WITH  (   
            [ BATCHSIZE [ = batch_size ] ],       
            [ CHECK_CONSTRAINTS ],           
            [ CODEPAGE [ = 'ACP' | 'OEM' | 'RAW' | 'code_page' ] ],   
            [ DATAFILETYPE [ = 'char' | 'native'| 'widechar' | 'widenative' ] ],               
            [ FIELDTERMINATOR [ = 'field_terminator' ] ],   
            [ FIRSTROW [ = first_row ] ],   
            [ FIRE_TRIGGERS ],   
            [ FORMATFILE = 'format_file_path' ],   
            [ KEEPIDENTITY ],   
            [ KEEPNULLS ],   
            [ KILOBYTES_PER_BATCH [ = kilobytes_per_batch ] ],      
            [ LASTROW [ = last_row ] ],   
            [ MAXERRORS [ = max_errors ] ],   
            [ ORDER ( { column [ ASC | DESC ] } [ ,...n ] ) ],     
            [ ROWS_PER_BATCH [ = rows_per_batch ] ],   
            [ ROWTERMINATOR [ = 'row_terminator' ] ],             
            [ TABLOCK ],   
    )  

相关参数说明:

BULK INSERT    
   [ database_name . [ schema_name ] . | schema_name . ] [ table_name | view_name ]    
      FROM 'data_file'    
     [ WITH    
        (    
   [ [ , ] BATCHSIZE = batch_size ]    --BATCHSIZE指令来设置在单个事务中可以插入到表中的记录的数量   
   [ [ , ] CHECK_CONSTRAINTS ]     --指定在大容量导入操作期间,必须检查所有对目标表或视图的约束。若没有 CHECK_CONSTRAINTS 选项,则所有 CHECK 和 FOREIGN KEY 约束都将被忽略,并且在此操作之后表的约束将标记为不可信。   
   [ [ , ] CODEPAGE = { 'ACP' | 'OEM' | 'RAW' | 'code_page' } ]  --指定该数据文件中数据的代码页   
   [ [ , ] DATAFILETYPE =    
      { 'char' | 'native'| 'widechar' | 'widenative' } ]  --指定 BULK INSERT 使用指定的数据文件类型值执行导入操作。   
   [ [ , ] FIELDTERMINATOR = 'field_terminator' ]  --标识分隔内容的符号   
   [ [ , ] FIRSTROW = first_row ]    --指定要加载的第一行的行号。默认值是指定数据文件中的第一行   
   [ [ , ] FIRE_TRIGGERS ]     --是否启动触发器   
   [ [ , ] FORMATFILE = 'format_file_path' ]    
   [ [ , ] KEEPIDENTITY ]   --指定导入数据文件中的标识值用于标识列   
   [ [ , ] KEEPNULLS ]    --指定在大容量导入操作期间空列应保留一个空值,而不插入用于列的任何默认值   
   [ [ , ] KILOBYTES_PER_BATCH = kilobytes_per_batch ]    
   [ [ , ] LASTROW = last_row ]   --指定要加载的最后一行的行号   
   [ [ , ] MAXERRORS = max_errors ]   --指定允许在数据中出现的最多语法错误数,超过该数量后将取消大容量导入操作。   
   [ [ , ] ORDER ( { column [ ASC | DESC ] } [ ,...n ] ) ]  --指定数据文件中的数据如何排序   
   [ [ , ] ROWS_PER_BATCH = rows_per_batch ]    
   [ [ , ] ROWTERMINATOR = 'row_terminator' ]   --标识分隔行的符号   
   [ [ , ] TABLOCK ]     --指定为大容量导入操作持续时间获取一个表级锁   
   [ [ , ] ERRORFILE = 'file_name' ]   --指定用于收集格式有误且不能转换为 OLE DB 行集的行的文件。   
        )]   
INSERT INTO Product(Id,Name,Price) VALUES(newid(),'牛栏1段',160);
INSERT INTO Product(Id,Name,Price) VALUES(newid(),'牛栏2段',260);
......

我的新书ASP.NET MVC企业级实战预计明年2月份出版,感谢大家关注!

方式四:拼接SQL

此种方法在C#中有限制,一次性只能批量插入1000条,所以就得分段进行插入。

        #region 方式四
        static void InsertFour()
        {
            Console.WriteLine("采用拼接批量SQL插入的方式实现");
            Stopwatch sw = new Stopwatch();

            using (SqlConnection conn = new SqlConnection(StrConnMsg)) //using中会自动Open和Close 连接。
            {
                conn.Open();
                sw.Start();
                for (int j = 0; j < totalRow / getRow;j   )
                {
                    StringBuilder sb = new StringBuilder();
                    sb.Append("INSERT INTO Product(Id,Name,Price) VALUES");
                    using (SqlCommand cmd = new SqlCommand())
                    {

                        for (int i = 0; i < getRow; i  )
                        {
                            sb.AppendFormat("(newid(),'商品{0}',{0}),", j*i i);
                        }
                        cmd.Connection = conn;
                        cmd.CommandText = sb.ToString().TrimEnd(',');
                        cmd.ExecuteNonQuery();
                    }
                }
                sw.Stop();
                Console.WriteLine(string.Format("插入{0}条记录,共耗时{1}毫秒",totalRow,sw.ElapsedMilliseconds));
            }
        }
        #endregion

运行结果如下:

上海时时乐走势图官网 10

我们可以看到大概花费了10分钟。虽然在方式一的基础上,性能有了较大的提升,但是显然还是不够快。

总结:大数据批量插入方式一和方式四尽量避免使用而方式二和方式三都是非常高效的批量插入数据方式。其都是通过构建DataTable的方式插入的,而我们知道DataTable是存在内存中的,所以当数据量特别特别大,大到内存中无法一次性存储的时候,可以分段插入。比如需要插入9千万条数据,可以分成9段进行插入,一次插入1千万条。而在for循环中直接进行数据库操作,我们是应该尽量避免的。每一次数据库的连接、打开和关闭都是比较耗时的,虽然在C#中存在数据库连接池,也就是当我们使用using或者conn.Close(),进行释放连接时,其实并没有真正关闭数据库连接,它只是让连接以类似于休眠的方式存在,当再次操作的时候,会从连接池中找一个休眠状态的连接,唤醒它,这样可以有效的提高并发能力,减少连接损耗。而连接池中的连接数,我们都是可以配置的。

源码下载:

先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的是GUID,表中没有创建任何索引。GUID必然是比自增长要快的,因为你生成一个GUID算法所花的时间肯定比你从数据表中重新查询上一条记录的ID的值然后再进行加1运算要少。而如果存在索引的情况下,每次插入记录都会进行索引重建,这是非常耗性能的。如果表中无可避免的存在索引,我们可以通过先删除索引,然后批量插入,最后再重建索引的方式来提高效率。

方式一:一条一条插入,性能最差,不建议使用。

本文由上海时时乐走势图发布于上海时时乐走势图官网,转载请注明出处:[Oracle] Bulk Insert Data上海时时乐走势图官网

您可能还会对下面的文章感兴趣: