我正在从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);
答案 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语句选择数据,但是使用数据集append
和fieldbyname()
方法进行插入。 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属性。这意味着对于您进行的每个写操作,数据库将对您的硬盘进行一次或多次写入,这很慢。通过显式创建事务(关闭自动提交...),您可以在事务中对写入操作进行分组,并且当您明确提交事务时,数据库可以向硬盘驱动器发出少得多的写入操作。