代码之家  ›  专栏  ›  技术社区  ›  silent

TClientDataSet和大插入

  •  3
  • silent  · 技术社区  · 15 年前

    在我的应用程序中,我使用TADOQuery和select(MSSQL)并将其链接到TClientDataSet。我必须插入大约一百万条记录和应用程序更新。

    每个

    一旦 对于插入前的所有记录,在插入后取消准备。我怎么做?

    添加在

    在查询中,我有一个用于执行存储过程的脚本:

    tmpQuery := DefineQuery(FConnection, [
      'exec up_getOperatorDataSet ',
      '  @tablename     = :tablename, ',
      '  @operator      = :operator, ',
      '  @forappend     = :forappend, ',
      '  @withlinksonly = :withlinksonly, ',
      '  @ids           = :ids '
    ], [
      Param(ftString, sTableName),
      Param(ftInteger, FOperatorId),
      Param(ftBoolean, opForAppendOnly in OpenParams),
      Param(ftBoolean, opOnlyWithModelLinks in OpenParams),
      Param(ftString, sIds)
    ], Result);
    

    它从表中选择所有字段 sTableName 有一些参数。

    从探查器插入的示例:

    declare @p1 int
    set @p1=486
    exec sp_prepare @p1 output,N'@P1 int,@P2 int,@P3 datetime,@P4 int,@P5 int,@P6 int,@P7 int,@P8 int,@P9 varchar(128),@P10 bit,@P11 numeric(19,4),@P12 smallint,@P13 smallint,@P14 smallint,@P15 smallint',N'insert into parser_prices
      (operator_id, request_id, date, nights, model_hotel_id, model_meal_id, model_room_id, model_htplace_id, spo, hotelstop, price, frout_econom, frout_business, frback_econom, frback_business)
    values
      (@P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8, @P9, @P10, @P11, @P12, @P13, @P14, @P15)
    ',1
    select @p1
    

    步骤2:

    exec sp_execute 486,21,2000450,'2009-12-04 00:00:00',14,2118,22,-9555,18,'2009-10.MSK.Bali.13.10.09-27.03.10',0,15530.0000,3,3,3,3
    

    步骤3:

    exec sp_unprepare 486
    

    总的来说 新的一行。

    4 回复  |  直到 15 年前
        1
  •  1
  •   J__    15 年前

    因为您调用的是存储过程,而不是代码中的内联查询,所以SQL Server会将对存储过程的每次调用视为单独的调用,每次都会准备和取消准备存储过程。我不确定是否有办法解决这个问题。

    如果存储过程中发生的任何事情都可以通过代码中的查询完成,那么您可以使用这样的结构,只在第一次准备SQL语句:

    {Prepare the insert query}
    ADOQuery1.SQL.Append('INSERT INTO Tablename');
    ADOQuery1.SQL.Append('(StringField1, IntField2)');             {repeat as necessary}
    ADOQuery1.SQL.Append('VALUES (:sFieldValue1, :sFieldValue2)'); {repeat as necessary}
    ADOQuery1.SQL.Prepare;
    
    {In a For, While, Repeat loop, use:}
    ADOQuery1.ParamByName('sFieldValue1').AsString := 'Value for field 1';
    ADOQuery1.ParamByName('sFieldValue2').AsInteger := 2;
    ADOQuery1.ExecSQL;
    

        2
  •  0
  •   gbn    15 年前

    思想。。。

    1. 您不需要准备存储过程调用。实际上,它已经准备好了。您可以在大多数客户端实现中关闭它。

    2. batch size limit (eg a single DB call) of 256 MB (假设默认的4k网络数据包)。

    3. 在其他客户端实现中,您可以设置“ batch size

        3
  •  0
  •   Noah    15 年前

    我认为其他答案可能有助于优化性能,尽管我认为您使用什么方法访问TClientDataSet并不重要,因为无论哪种方式,实际的数据库更新都是独立的(并且是自动生成的)。

    如果更新作为每行的单独准备工作,那么Borland的设计选择似乎很糟糕,因为很明显,更新许多行将需要相同的查询,每次只使用不同的参数。

    另一方面,TClientDataSet用于内存中的数据库,这意味着相对较小的数据库。使用大约一百万行可能超出了预期的用例。

        4
  •  0
  •   silent    15 年前

    答案是在TADOConnection中使用的提供者中。从MSDASQL切换到SQLOLEDB,现在一切正常,没有任何其他查询。