为什么记录添加得这么慢

时间:2013-10-11 13:44:08

标签: sqlite delphi sql-server-2005 freepascal

我正在从SQL Server 2005中读取记录,并使用以下代码将返回的记录集写入SQLite。

我的编译器是Lazarus 1.0.12而qt1是“sqlquery”而且“qrystkmas”是来自Zeos dbo的Ztable ......

但操作很慢。测试时间是

开始时间:15:47:11 完成时间:16:19:04 记录数为:19500

因此在SQL Server和SQL Server CE对中,Delphi项目不到2-3分钟。

如何加快这个过程?

代码:

  Label2.Caption:=TimeToStr(Time);
  if Dm.Qt1.Active then Dm.Qt1.Close;
    Dm.Qt1.SQL.Clear;
    Dm.Qt1.SQL.Add('  select ');
    Dm.Qt1.SQL.Add('   st.sto_kod, st.sto_isim,st.sto_birim1_ad,  ');
    Dm.Qt1.SQL.Add('   st.sto_toptan_vergi,st.sto_perakende_vergi,');
    Dm.Qt1.SQL.Add('   st.sto_max_stok,st.sto_min_stok, ');
    Dm.Qt1.SQL.Add('   sba.bar_kodu,   ');
    Dm.Qt1.SQL.Add('   stf.sfiyat_fiyati  ');
    Dm.Qt1.SQL.Add('  from MikroDB_V14_DEKOR2011.dbo.STOKLAR st ');
    Dm.Qt1.SQL.Add('  left JOIN MikroDB_V14_DEKOR2011.dbo.BARKOD_TANIMLARI sba on sba.bar_stokkodu=st.sto_kod ');
    Dm.Qt1.SQL.Add('  left JOIN MikroDB_V14_DEKOR2011.dbo.STOK_SATIS_FIYAT_LISTELERI stf on stf.sfiyat_stokkod=st.sto_kod  ');
    Dm.Qt1.SQL.Add('  where LEFT(st.sto_kod,1)=''5'' --and stf.sfiyat_listesirano=1 ');
    Dm.Qt1.Open;
    Dm.qryStkMas.Open;
    Dm.qrystkmas.First;

    While not Dm.Qt1.EOF do
    begin
      Dm.qryStkMas.Append;
      Dm.qryStkMas.FieldByName('StkKod').AsString :=Dm.Qt1.FieldByName('sto_kod').AsString;
      Dm.qryStkMas.FieldByName('StkAd').AsString  :=Dm.Qt1.FieldByName('sto_isim').AsString;
      Dm.qryStkMas.FieldByName('StkBrm').AsString :=Dm.Qt1.FieldByName('sto_birim1_ad').AsString;
      Dm.qryStkMas.FieldByName('StkBar').AsString :=Dm.Qt1.FieldByName('bar_kodu').AsString;
      Dm.qryStkMas.FieldByName('StkKdv1').AsFloat :=Dm.Qt1.FieldByName('sto_toptan_vergi').AsFloat;
      Dm.qryStkMas.FieldByName('StkKdv2').AsFloat :=Dm.Qt1.FieldByName('sto_perakende_vergi').AsFloat;
      Dm.qryStkMas.FieldByName('StkGir').AsFloat  :=0;
      Dm.qryStkMas.FieldByName('StkCik').AsFloat  :=0;
      Dm.qryStkMas.FieldByName('YeniStk').AsBoolean :=False;
      Dm.qryStkMas.FieldByName('MinStk').AsFloat  :=Dm.Qt1.FieldByName('sto_min_stok').AsFloat;
      Dm.qryStkMas.FieldByName('MaxStk').AsFloat  :=Dm.Qt1.FieldByName('sto_max_stok').AsFloat;
      Dm.qryStkMas.FieldByName('StkGrp1').AsString:='';
      Dm.qryStkMas.FieldByName('StkGrp2').AsString:='';
      Dm.qryStkMas.FieldByName('StkGrp3').AsString:='';
      Dm.qryStkMas.FieldByName('StkGrp4').AsString:='';
      Dm.qryStkMas.FieldByName('StkFytno').AsInteger:=1;
      Label1.Caption:=Dm.Qt1.FieldByName('sto_isim').AsString;
      Dm.qryStkMas.Post;
      Dm.Qt1.Next;
    end;
    Dm.qryStkMas.Close;
   label3.Caption:=timetostr(time);

2 个答案:

答案 0 :(得分:4)

加快速度的第一步是诊断。

<强>测量
您可以通过拆分选择和插入来进行测量,但您也可以通过SQL本身获得一些诊断信息。

如果在SQLite中使用关键字EXPLAIN作为前缀,它将告诉您使用哪些索引以及如何在内部处理语句,请参见此处:http://www.sqlite.org/eqp.html
这是优化的宝贵信息 在MS SQL Server中,您进入gui,输入查询并单击估计的查询计划按钮,请参阅:what is the equivalent of EXPLAIN form SQLite in SQL Server?

花费的时间最多?是select慢还是insert

选择
选择通常通过将索引放在那些被评估的字段上来加速 在您的情况下,参与连接标准的字段 where子句中的字段使用一个函数,你不能在MSSQL中的函数上放置索引(你可以在PostgreSQL和Oracle中)。

插入
通过禁用索引加快插入速度 一个常见的技巧是在插入批处理之前禁用所有索引,并在插入批处理完成后重新启用它们 这通常更有效,因为它更快(每个项目)一次性整理整体,以便在每次插入后继续求助。

您还可以禁用交易安全措施 如果出现问题或电源/磁盘等故障,这将损坏您的数据,因此请考虑自己发出警告,请参阅此处:Improve large data import performance into SQLite with C#

对代码的评论
您可以使用SQL select语句选择数据,但是使用数据集appendfieldbyname()方法进行插入。 FieldByName非常慢,因为它每次都会进行名称查找 FieldByName永远不应该在循环中使用
而是构造一个insert SQL语句 请记住,您可以使用参数,甚至可以将值粘贴在那里 做一些实验,看看哪个更快。

About.com上有一篇关于如何通过消除FieldByName加速数据库访问的好文章:http://delphi.about.com/od/database/ss/faster-fieldbyname-delphi-database.htm

答案 1 :(得分:3)

您是否尝试过在事务中包装插入内容?您需要在您的While ...之前开始交易,并在......结束后执行COMMIT。试试吧,它可能有所帮助。

编辑:如果你得到了改进,那将是因为你的SQLite数据库连接是在“自动提交”模式下设置的,其中每个操作(例如你的.Append)都是与所有其他操作独立完成的,而SQLite则是足够聪明,可以确保数据库的ACID属性。这意味着对于您进行的每个写操作,数据库将对您的硬盘进行一次或多次写入,这很慢。通过显式创建事务(关闭自动提交...),您可以在事务中对写入操作进行分组,并且当您明确提交事务时,数据库可以向硬盘驱动器发出少得多的写入操作。