- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 Delphi XE8 和 FireDAC 来加载大型 SQLite 数据库。为此,我使用数组 DML 执行技术一次有效地插入大量记录,如下所示:
FDQueryAddINDI.SQL.Text := 'insert into indi values ('
+ ':indikey, :hasdata, :gedcomnames, :sex, :birthdate, :died, '
+ ':deathdate, :changed, :eventlinesneedprocessing, :eventlines, '
+ ':famc, :fams, :linkinfo, :todo, :nextreportindi, :firstancestralloop'
+ ')';
FDQueryAddINDI.Params.Bindmode := pbByNumber; {more efficient than by name }
FDQueryAddINDI.Params.ArraySize := MaxParams; { large enough to load all of them }
NumParams := 0;
repeat
{ the code to determin IndiKey,... is not shown, but goes here }
FDQueryAddINDI.Params[0].AsStrings[NumParams] := IndiKey;
FDQueryAddINDI.Params[1].AsIntegers[NumParams] := HasData;
FDQueryAddINDI.Params[2].AsStrings[NumParams] := GedcomNames;
FDQueryAddINDI.Params[3].AsStrings[NumParams] := Sex;
FDQueryAddINDI.Params[4].AsStrings[NumParams] := Birthdate;
FDQueryAddINDI.Params[5].AsIntegers[NumParams] := Died;
FDQueryAddINDI.Params[6].AsStrings[NumParams] := Deathdate;
FDQueryAddINDI.Params[7].AsStrings[NumParams] := Changed;
FDQueryAddINDI.Params[8].AsIntegers[NumParams] := EventLinesNeedProcessing;
FDQueryAddINDI.Params[9].AsStrings[NumParams] := EventLines;
FDQueryAddINDI.Params[10].AsIntegers[NumParams] := FamC;
FDQueryAddINDI.Params[11].AsIntegers[NumParams] := FamS;
FDQueryAddINDI.Params[12].AsIntegers[NumParams] := Linkinfo;
FDQueryAddINDI.Params[13].AsIntegers[NumParams] := ToDo;
FDQueryAddINDI.Params[14].AsIntegers[NumParams] := NextReportIndi;
FDQueryAddINDI.Params[15].AsIntegers[NumParams] := FirstAncestralLoop;
inc(NumParams);
until done;
FDQueryAddINDI.Params.ArraySize := NumParams; { Reset to actual number }
FDQueryAddINDI.Execute(LogoAppForm.FDQueryAddINDI.Params.ArraySize);
将数据实际加载到 SQLite 数据库中的速度非常快,我对此速度没有任何问题。
让我放慢速度的是在重复循环中将所有值分配给参数所花费的时间。
参数内置于 FireDAC 中,是一个 TCollection。我无权访问源代码,因此我看不到 AsStrings 和 AsIntegers 方法实际上在做什么。
在我看来,为每次插入的每个参数分配每个值并不是加载此 TCollection 的非常有效的方法。有没有更快的方法来加载这个?我在想也许有一种方法可以一次加载一整套参数,例如(IndiKey、HasData、...FirstAncestralLoop)全部为一体。或者也许尽可能高效地加载我自己的 TCollection,然后使用 TCollection 的分配方法将我的 TCollection 复制到 FireDAC 的 TCollection 中。
所以我的问题是加载 FireDAC 所需的参数 TCollection 的最快方法是什么?
<小时/>更新:我添加了 Arnaud 的一些计时。
如 Using SQLite with FireDAC 中所述(请参阅其数组 DML 部分):
Starting with v 3.7.11, SQLite supports the INSERT command with multiple VALUES. FireDAC uses this feature to implement Array DML, when Params.BindMode = pbByNumber. Otherwise, FireDAC emulates Array DML.
我已经测试插入 33,790 条记录,更改数组大小(每次执行加载的记录数),并使用 pbByName(用于模拟)和 pbByNumber(使用多个值插入)计时加载时间。
时间是这样的:
Arraysize: 1, Executes: 33,790, Timing: 1530 ms (pbByName), 1449 ms (pbByNumber)
Arraysize: 10, Executes: 3,379, Timing: 1034 ms (pbByName), 782 ms (pbByNumber)
Arraysize: 100, Executes: 338, Timing: 946 ms (pbByName), 499 ms (pbByNumber)
Arraysize: 1000, Executes: 34, Timing: 890 ms (pbByName), 259 ms (pbByNumber)
Arraysize: 10000, Executes: 4, Timing: 849 ms (pbByName), 227 ms (pbByNumber)
Arraysize: 20000, Executes: 2, Timing: 594 ms (pbByName), 172 ms (pbByNumber)
Arraysize: 50000, Executes: 1, Timing: 94 ms (pbByName), 94 ms (pbByNumber)
现在,这些计时的有趣之处在于,每次测试运行将这 33,790 条记录加载到 TCollection 中需要整整 93 毫秒。无论是一次添加 1 个还是一次添加 10000 个,填充 TCollection 参数的开销始终存在。
为了进行比较,我做了一个更大的测试,仅针对 pbByNumber 插入了 198,522 次:
Arraysize: 100, Executes: 1986, Timing: 2774 ms (pbByNumber)
Arraysize: 1000, Executes: 199, Timing: 1371 ms (pbByNumber)
Arraysize: 10000, Executes: 20, Timing: 1292 ms (pbByNumber)
Arraysize: 100000, Executes: 2, Timing: 894 ms (pbByNumber)
Arraysize: 1000000, Executes: 1, Timing: 506 ms (pbByNumber)
对于此测试的所有情况,加载 TCollection of Params 的开销大约需要 503 毫秒。
因此,TCollection 的加载速度似乎约为每秒 400,000 条记录。这是插入时间的一个重要部分,一旦我开始使用数百万的大型数据库,这个增加的时间对于我的程序的用户来说将是相当明显的。
我想改进这一点,但我还没有找到加快参数加载速度的方法。
<小时/>更新 2:通过将所有代码放在 StartTransaction 和 Commit 之间,我能够获得大约 10% 的时间改进,以便立即处理所有 block 。
但我仍在寻找某种方法来更快地加载 TCollection of Params。
<小时/>另一个想法:
如果可能的话,什么可能工作得很好并且速度可以提高 16 倍,类似于 the ParamValues method 。这会一次分配多个参数,并具有直接提供变体数组的额外优势,并且避免了转换值的需要。
它会像这样工作:
FDQueryAddINDI.Params.ParamValues['indikey;hasdata;gedcomnames;sex;birthdate;died;deathdate;changed;eventlinesneedprocessing;eventlines;famc;fams;linkinfo;todo;nextreportindi;firstancestralloop']
:= VarArrayOf([Indikey, 0, ' ', ' ', ' ', 0, ' ', ' ', 1, ' ', -1, -1, -1, -1, -1, -1]);
但是,ParamValues 只会分配给第一组参数,即 NumIndiParms = 0。
有没有办法对循环中的每个索引(即 NumIndiParms 的每个实例)执行此操作?
<小时/>赏金:我真的很想加快参数的加载速度。我现在向某人提供悬赏,帮助我找到一种加快 FireDAC 中实现的 Params 数组 TCollection 加载速度的方法。
最佳答案
对我来说听起来有点像过早优化。恕我直言,探查器会显示 repeat ....until done
循环比 Execute
调用本身花费的时间少得多。分配整数
几乎是即时的,就像分配字符串
一样,这要归功于 CopyOnWrite Delphi string
类型的范例,通过引用复制文本。
请注意,实际上,SQLite3 中没有数组 DML 功能。 FireDac 通过创建多个插入来模拟数组 DML,即执行
insert into indi values (?,?,?,....),(?,?,?,....),(?,?,?,....),....,(?,?,?,....);
据我所知,这是使用 SQLite3 插入数据最快的方法。至少直到 upcoming OTA feature可用。
还要确保将插入嵌套在多个事务中,并且一次设置的参数数量不要太多。根据我的测试,如果您有很多行要插入,您还应该创建多个事务。维护单个事务会减慢流程。根据实验,每个事务 10000 行是一个不错的数字。
顺便说一句,我们的 ORM 能够做到所有 this low-level plumbing取决于它运行的后端引擎。
更新:听起来 FireDac 参数在您的情况下可能是真正的瓶颈。因此,您应该绕过 FireDAC,并直接将您的 TCollection
内容与 SQlite3 引擎绑定(bind)。尝试例如our SynSQLite3.pas unit 。请记住使用多重插入来准备 INSERT 语句 ((?,?,?,....),(?,?,?,....),....
) ,然后直接绑定(bind)您的值。 BTW DB.pas
可能是一个真正的瓶颈,这就是为什么我们的整个 ORM 绕过这一层(但如果需要的话可以使用它)。
更新2:既然您要求,这里是使用mORMot的版本。
首先定义您的记录:
type
TSQLIndy = class(TSQLRecord)
...
published
property indikey: string read findikey write findikey;
property hasdata: boolean read fhasdata write fhasdata;
property gedcomnames: string read fgedcomnames write fgedcomnames;
property sex: string read fsex write fsex;
property birthdate: string read fbirthdate write fbirthdate;
property died: boolean read fdied write fdied;
...
end;
然后通过 ORM 运行插入:
db := TSQLRestServerDB.CreateWithOwnModel([TSQLIndy],'test.db3');
db.CreateMissingTables; // will CREATE TABLE if not existing
batch := TSQLRestBatch.Create(db,TSQLIndy,10000);
try
indy := TSQLIndy.Create;
try
for i := 1 to COUNT do begin
indy.indikey := IntToString(i);
indy.hasdata := i and 1=0;
...
batch.Add(indy,true);
end;
finally
indy.Free;
end;
db.BatchSend(batch);
完整的源代码是available online on paste.ee .
以下是 1,000,000 条记录的时间:
Prepared 1000000 rows in 874.54ms
Inserted 1000000 rows in 5.79s
如果我算得好的话,每秒插入超过170,000行。在这里,ORM 不是一种开销,而是一种优势。所有多 INSERT 工作、事务(每 10000 行)、编码将由框架完成。 TSQLRestBatch
会将所有内容以 JSON 形式存储在内存中,然后立即计算 SQL。我很好奇直接 FireDAC 相比之下表现如何。如果需要,您可以切换到其他数据库 - 另一个 RDBMS(MySQL、Oracle、MSSQL、FireBird)甚至 MongoDB。只需添加一个新行。
希望对你有帮助!
关于performance - 在 Delphi FireDAC 中加载数组 DML 的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31522523/
什么是更快的安卓? Color.rgb(184, 134, 011); 或 Color.parseColor("#234181"); 还是别的什么? 答案:最快的似乎是: int mycolor =
没错, 基本上我需要计算出从服务器到最终用户的最短路线。我有 2 台服务器 - 一台在英国,一台在美国。 我需要根据最终用户的位置确定从哪个服务器加载内容。 我最初想使用 fsock/curl/fgc
我正在阅读固定宽度整数类型 ( cpp reference) 并遇到int_fast8_t、int_fast16_t、int_fast32_t 和 int_least8_t 类型,int_least1
Closed. This question is opinion-based。它当前不接受答案。 想改善这个问题吗?更新问题,以便editing this post用事实和引用来回答。 6年前关闭。
我有大量目录,我想尽快读取所有文件。我的意思是,不是 DirectoryInfo.GetFiles 快,而是“get-clusters-from-disk-low-level”快。 当然,.NET 2
我尝试寻找最小的可被1到n整除的数字,现在我正在寻求有关进一步压缩/使我的解决方案更有效的方法的建议。如果也有O(1)解决方案,那将非常酷。 def get_smallest_number(n):
有很多不同的方法可以在驱动程序之间选择元素。我想知道哪一个最快且最适合 native 应用程序(iOS 和 Android)。 Appium Driver 类有: findElementByAcces
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,
让矩阵 A 说 A = magic(100);。我见过两种计算矩阵 A 的所有元素之和的方法。 sumOfA = sum(sum(A)); 或者 sumOfA = sum(A(:)); 其中一个比另一
我想为玩具车在没有障碍物的平面 (2d) 上规划一条路线。玩具车应该从点 (p1x,p1y) 移动到 (p2x,p2y)(又名狄利克雷边界条件)。此外,玩具车在起点的速度是(v1x,v1y),终点处要
假设有 n 个 3 维对象(多面体)。最快的方法是计算所有对象的交集O(n^2)? 现在,我正在使用一个基本上强制 T(n) 等于 n ^ 2 的库: for each object: // ther
关闭。这个问题需要 details or clarity 。它目前不接受答案。 想改进这个问题吗? 添加细节并通过 editing this post 澄清问题。 关闭 5 年前。 Improve
在 c: 上,我有数以万计的 *.foobar 文件。它们在各种各样的地方(即子目录)。这些文件的大小大约为 1 - 64 kb,并且是纯文本。 我有一个 class Foobar(string fi
我的基本问题是有多个线程做一些事情,其中一些需要比其他线程更多的时间(20 倍甚至更多),他们需要的时间只取决于起始值,但不能从起始值预测单独他们需要多少时间。为了减少更快线程的空闲时间,我想通过
好的,我有一个疑问: select distinct(a) from mytable where b in (0,3) 什么会更快,上面的还是 select distinct(a) from myta
问题简介: 我正在开发一个生态生理模型,我使用了一个名为 S 的引用类列表。存储模型需要输入/输出的每个对象(例如气象、生理参数等)。 此列表包含 5 个对象(请参见下面的示例): - 两个数据帧,S
我有一个正在工作的问题陈述,但我仍然想知道更高效、更快,更重要的是正确设计来处理下面提到的场景。 我有一个 POJO 类 class A { String s; Double d; } 我正在
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 3 年前。 Improve this q
关于 LLVM 如何优化代码,关于 SO 以及整个网络都有一些非常好的描述。但这些都无法回答我的具体问题。 在 Xcode 中,项目和目标设置中有各种代码优化选项。我理解在开发过程中不需要优化,但为什
我正在用 C# 开发一个服务器项目,在收到 TCP 消息后,它会被解析并存储在一个精确大小的 byte[] 中。 (不是固定长度的缓冲区,而是存储所有数据的绝对长度的字节[]。) 现在为了阅读这个 b
我是一名优秀的程序员,十分优秀!