0

我正在从 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);
4

2 回答 2

4

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

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

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

什么东西花的时间最多?是select慢还是insert

SELECT
选择通常通过在那些被评估的字段上放置索引来加速。
在您的情况下,连接条件中涉及的字段。
where 子句中的字段使用函数,您不能在 MSSQL 中的函数上放置索引(您可以在 PostgreSQL 和 Oracle 中)。

INSERT通过禁用索引
来加速插入。 一个常见的技巧是在插入批处理之前禁用所有索引,并在插入批处理完成后重新启用它们。 这通常更有效,因为它可以更快地(每个项目)一次性对整体进行排序,以便在每个单独的插入之后继续使用。

您还可以禁用事务保护。
这将损坏您的数据以防万一或电源/磁盘等故障,因此请考虑警告自己,请参阅此处:使用 C# 提高大数据导入 SQLite 的性能

代码注释
您使用 SQL 选择语句选择数据,但是您使用数据集appendfieldbyname()方法插入。FieldByName 是出了名的慢,因为它每次都会进行名称查找。
FieldByName 不应该在循环中使用,
而是 构造一个insertSQL 语句。
请记住,您可以使用参数,甚至可以在其中硬粘贴值。
做一些实验,看看哪个更快。

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

于 2013-10-11T14:24:32.427 回答
3

您是否尝试将插入包装在事务中?您需要在您的 While... 之前开始一个事务,并在 ...End 之后提交它。试试看,它可能会有所帮助。

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

于 2013-10-11T14:16:52.477 回答