使用ADO插入许多记录

时间:2010-03-23 22:05:51

标签: delphi ado

我正在寻找使用 ADO 一次将多个记录(+1000)插入表格的最快方法。

选项:

  1. 使用插入命令和参数

    ADODataSet1.CommandText:='INSERT INTO .....';    
    ADODataSet1.Parameters.CreateParameter('myparam',ftString,pdInput,12,''); 
    ADODataSet1.Open;
    
  2. 使用TAdoTable

    AdoTable1.Insert;
    AdoTable1.FieldByName('myfield').Value:=myvale;
    //..
    //..
    //..
    AdoTable1.FieldByName('myfieldN').value:=myvalueN;
    AdoTable1.Post;
    
  3. 我使用的是delphi 7,ADO和ORACLE。

8 个答案:

答案 0 :(得分:3)

可能您的最快方式是选项2.插入所有记录并告诉数据集将其发送到数据库。但是FieldByName很慢,你可能不应该在像这样的大循环中使用它。如果您已经有了字段(因为它们是在设计时定义的),请在代码中引用它们的实际名称。如果没有,请为每个字段调用一次FieldByName并将它们存储在局部变量中,并在插入时引用这些字段。

答案 1 :(得分:2)

使用ADO我觉得你可能运气不好。并非所有后端都支持批量插入操作,因此ADO实现抽象以允许明显批量操作(批处理)的一致编码,而不管后端支持“引擎盖下”仅插入“批处理”作为一大堆参数化的单独插入。

这样做的缺点是即使那些支持批量插入的后端也不总是将其编码到他们的ADO / OLEDB提供商中 - 为什么这么麻烦? (我已经看到它提到Oracle OLEDB提供程序支持批量操作,并且ADO拒绝访问它,因此甚至可能ADO框架不允许提供程序在ADO本身中更直接地支持此功能 - 我不确定。)

但是,你提到了Oracle,这个后端肯定 通过它的原生API支持批量插入操作。

There is a commercial Delphi component library - ODAC (Oracle Direct Access Components) for, um, direct access to Oracle (it does not even require the Oracle client software to be installed)

这也直接支持Oracle提供的批量插入功能,并且是访问Oracle数据存储的高效方法。

答案 2 :(得分:1)

您要做的是bulk insert。 Oracle提供了可用于此目的的.NET程序集Oracle.DataAccess.dll您可以想到没有手动制作的解决方案会超过Oracle DBMS的自定义供应商库的性能。

http://download.oracle.com/docs/html/E10927_01/OracleBulkCopyClass.htm#CHDGJBBJ

http://dotnetslackers.com/articles/ado_net/BulkOperationsUsingOracleDataProviderForNETODPNET.aspx

最常见的想法是为每列使用值数组并将它们应用于模板SQL。在下面的示例中,employeeIds,firstNames,lastNames和dobs是具有要插入的值的相同长度的数组。

  

ODP.NET中的数组绑定功能   允许您插入多个记录   在一个数据库调用中。要使用Array   绑定,你只需设置   OracleCommand.ArrayBindCount为   要插入的记录数,以及   将值数组作为参数传递   而不是单个值:

> 01. string sql =
> 02. "insert into bulk_test (employee_id, first_name, last_name,
> dob) "
> 03.
> + "values (:employee_id, :first_name, :last_name, :dob)";
> 04.
>  
> 05. OracleConnection cnn = new OracleConnection(connectString);
> 06. cnn.Open();
> 07. OracleCommand cmd = cnn.CreateCommand();
> 08. cmd.CommandText = sql;
> 09. cmd.CommandType = CommandType.Text;
> 10. cmd.BindByName = true;
> 11.
>  
> 12. // To use ArrayBinding, we need to set ArrayBindCount
> 13. cmd.ArrayBindCount = numRecords;
> 14.
>  
> 15. // Instead of single values, we pass arrays of values as parameters
> 16. cmd.Parameters.Add(":employee_id", OracleDbType.Int32,
> 17. employeeIds, ParameterDirection.Input);
> 18. cmd.Parameters.Add(":first_name", OracleDbType.Varchar2,
> 19. firstNames, ParameterDirection.Input);
> 20. cmd.Parameters.Add(":last_name", OracleDbType.Varchar2,
> 21. lastNames, ParameterDirection.Input);
> 22. cmd.Parameters.Add(":dob", OracleDbType.Date,
> 23. dobs, ParameterDirection.Input);
> 24. cmd.ExecuteNonQuery();
> 25. cnn.Close();
  

正如您所看到的,代码看起来并没有太大的不同   从做一个普通的单一记录   插入。但是,表现   改善非常激烈,   取决于记录的数量   参与其中。您需要的记录越多   插入,性能越大   获得。在我的开发PC上,插入   使用Array Binding的1,000条记录是   比插入快90倍   一次记录一个。是的,你看了   那个权利:快了90倍!您的   结果会有所不同,具体取决于   记录大小和网络   数据库的速度/带宽   服务器

     

一些调查工作显示   SQL被认为是   多次“执行”   服务器端。证据来自   V $ SQL(查看EXECUTIONS列)。   但是,从.NET的角度来看,   一切都是在一个电话中完成的。

答案 3 :(得分:1)

您可以直接使用TADOConnection对象来提高插入性能。

dbConn := TADOConnection......
dbConn.BeginTrans;
try
  dbConn.Execute(command, cmdText, [eoExecuteNoRecords]);
  dbConn.CommitTrans;
except
  on E:Exception do
  begin
    dbConn.RollbackTrans;
    Raise e;
  end;
end;

此外,通过一次插入多个记录可以进一步提高速度。

答案 4 :(得分:0)

您还可以尝试TADODataset的BatchOptmistic模式。我没有Oracle所以不知道它是否支持Oracle,但我使用了类似的MS SQL Server。

ADODataSet1.CommandText:='select * from  .....';
ADODataSet1.LockType:=ltBatchOptimistic;
ADODataSet1.Open;

ADODataSet1.Insert;
ADODataSet1.FieldByName('myfield').Value:=myvalue1;
//..
ADODataSet1.FieldByName('myfieldN').value:=myvalueN1;
ADODataSet1.Post;

ADODataSet1.Insert;
ADODataSet1.FieldByName('myfield').Value:=myvalue2;
//..
ADODataSet1.FieldByName('myfieldN').value:=myvalueN2;
ADODataSet1.Post;

ADODataSet1.Insert;
ADODataSet1.FieldByName('myfield').Value:=myvalue3;
//..
ADODataSet1.FieldByName('myfieldN').value:=myvalueN3;
ADODataSet1.Post;


// Finally update Oracle with entire dataset in one batch
ADODataSet1.UpdateBatch(arAll);

答案 5 :(得分:0)

1000行可能不是这种方法变得经济的点,但考虑将插入物写入平面文件&然后运行SQL * Loader命令行实用程序。这是将数据批量上传到Oracle的最快方法。

http://www.oracleutilities.com/OSUtil/sqlldr.html

我见过开发人员花了几周的时间编写(Delphi)加载例程,这些例程的执行速度比控制文件控制的SQL * Loader慢了几个数量级,而控制文件花了大约一个小时才能写入。

答案 6 :(得分:0)

请记住禁用链接到数据集/表/查询/...

的可能控件
...
ADOTable.Disablecontrols;
try
   ...
finally
   ADOTable.enablecontrols;
end;
...

答案 7 :(得分:0)

您可以尝试附加而不是插入:

AdoTable1.Append;
AdoTable1.FieldByName('myfield').Value:=myvale;
//..
//..
//..
AdoTable1.FieldByName('myfieldN').value:=myvalueN;
AdoTable1.Post;

使用Append,您将在客户端数据集上节省一些精力,因为记录将添加到最后,而不是插入记录并推倒其余部分。

此外,您可以解除可能绑定到数据集的任何数据感知控件或使用BeginUpdate锁定它们。

我在append方法中获得了相当不错的性能,但如果您期望批量速度,您可能希望通过执行查询本身来查看在单个查询中插入多行:

AdoQuery1.SQL.Text = 'INSERT INTO myTable (myField1, myField2) VALUES (1, 2), (3, 4)';
AdoQuery1.ExecSQL;

一次插入多个记录时,您应该从数据库引擎中获得一些好处。