|
|
导航: |
论坛 -> 数据库专区
斑竹:liumazi,waterstone |
|
作者: |
|
2024/3/2 13:26:40 |
标题: |
请教一下,关于FireDac+Sqlite+DML写入数据后,数据库文件很大的问题 |
浏览:345 |
|
加入我的收藏 |
楼主: |
操作:使用下面代码写入 200w 条记录(分20次,因内存抵不住) 问题:生成的数据库Db文件很大,而且DB文件大小,时大时小,有时700M(偶尔),有时1100M(大部分时间),但数据查到是一样的; 请教:我想数据库文件比较小,如700M以下,不知道哪里可以优化一下; 请问这种一次性写入 100~2000w 数据写入 Db,有没有什么好建议可以提供?
谢谢...
1:D11/12:FireDac+Sqlite 代码建库 FCon1:= TFDConnection.Create(Nil); with FCon1 do begin Connected := False; Params.Values['DriverID'] := 'SQLite'; Params.Values['Database'] := 'D:\123.db'; Params.Values['OpenMode'] := 'CreateUTF8'; Params.Values['StringFormat'] := 'Unicode'; Connected := True; end;
FCon1.ExecSQL('CREATE TABLE ABC(AA TEXT, BB INT64)'); //没有索引,没有自动ID
FQ1:= TFDQuery.Create(nil); with FQ1 do begin Close; Connection := FCon1; IndexesActive:=False; AutoCalcFields:=False; CachedUpdates:=True; FetchOptions.Mode := fmManual; FetchOptions.AutoFetchAll:= afDisable; FetchOptions.RecordCountMode := cmVisible; FetchOptions.CursorKind := ckForwardOnly; FetchOptions.Unidirectional:=True; FetchOptions.AutoClose := False; ResourceOptions.SilentMode := True; end;
2:循环 i 次,使用 DML 批量写入:
T1:0~512长度的字符串 ,各国文字串 F1:0~100亿的数字长度
For i := 0 to 20-1 do // i = 0~200 begin FCon1.StartTransaction;
FQ1.DisableControls; FQ1.SQL.Text :='insert into ABC(AA TEXT, BB INT64) values (:s1, :s2)'; FQ1.Params.BindMode := pbByNumber; FQ1.Params.ArraySize := 100000; //10w~20w
for j :=0 to (100000-1) do //这里会动态套入不重复 begin FQ1.Params[0].AsStrings[j] := T1; FQ1.Params[1].AsLargeInts[j] := F1; end;
FQ1.Execute(100000, 0);
FCon1.Commit; //要每次都提交数据库,否则内存不足 FCon1.Close; //不知道哪里设置问题,必须Close才会写入DB,否则只会留在内存,直至溢出内存 end;
----------------------------------------------
阳光总在 |
作者: |
hncsl (hncsl) |
★☆☆☆☆ |
-
|
普通会员 |
|
2024/3/3 9:06:18 |
1楼: |
if not FDConnection1.Connected then FDConnection1.Connected := True;
sTxt := 'insert into ABC(AA, BB) values (:s1, :s2)'; FDConnection1.StartTransaction; try for i := 0 to 100000 do // 这里会动态套入不重复 (100000-1) begin F1 := Randomrange(0, 65535); T1 := 'sssss'; FDQuery1.SQL.Text := sTxt; FDQuery1.ParamByName('s1').DataType := ftString; FDQuery1.ParamByName('s2').DataType := ftInteger; FDQuery1.Prepare; FDQuery1.ParamByName('s1').AsString := T1; FDQuery1.ParamByName('s2').AsInteger := F1; FDQuery1.ExecSQL; end; FDConnection1.Commit;
ShowMessage('Inserted ' + i.ToString + ' Records!') ; except on E: Exception do begin FDConnection1.Rollback; ShowMessage(E.Message); end;
end; 这个测试未关闭FDConnection1时,可以直接写入;如大批量插入,还是使用批量插入的SQL语句。
----------------------------------------------
-
|
作者: |
|
2024/3/3 11:15:03 |
2楼: |
楼主说:
//不知道哪里设置问题,必须Close才会写入DB,否则只会留在内存,直至溢出内存
---------- 你是不是设置了 CatchedUpdate 为 True?
----------------------------------------------
-
|
作者: |
yookee (yookee) |
★☆☆☆☆ |
-
|
盒子活跃会员 |
|
2024/3/3 11:26:31 |
2楼: |
FireDac+Sqlite+DML的上限不应该这么低 我曾经用过 FQ1.Params.ArraySize := N1; // N1>5e7,为了应对偶尔碰到的数据风暴 实际 FQ1.Execute(N2, 0); // N2>5e5
你是用64bit编译的吗,我做上述操作时程序占用内存峰值过8G了,生成的数据库文件500M左右。你的T1较长时,我估计机子配32G的内存肯定够用的。
如果你是反复删除插入数据,在意数据库大小的话,每次重新大量插入前用VACUUM清理一下
----------------------------------------------
-
|
|