DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: webb123
今日帖子: 9
在线用户: 25
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 kylix2008 (kylix2008) ★☆☆☆☆ -
普通会员
2016/11/30 20:34:54
标题:
解决TClientDataSet导入大数据内存不足的BUG 浏览:5811
加入我的收藏
楼主: 一历史程序,采用UniDac直连Oracle数据库,大量使用TClientDataSet作为数据中转组件。

使用三层开发,只是利用了midas高效打包二进制数据的方式,
将TDataSetProvider组件的Data属性值,传到客户端:

CDS := DataSetProvider.Data;

客户端再用TClientDataSet导入,

ClientDataSet.Data := CDS;

然后处理数据(比如将ClientDataSet中数据再次导入客户端数据库,导入完毕释放掉ClientDataSet,再用客户端数据库进行其他处理)


数据量不太大时ClientDataSet.Data := CDS;速度非常快,效率高(比转成XML、JSON效率高)。

当CDS很大的时候(大于53M时,有时业务需要获取很大数据到客户端再处理,别说分页存取之类的话),
ClientDataSet.Data := CDS;
会出错:Out of memory:insufficient memory for this operation

采用ClientDataSet.LoadFromFile也一样出错。
XE3和XE7下都会出错。其他版本没测试。

找了好久,没找到其他数据集组件能够像ClientDataSet那样载入CDS。


另外,TClientDataSet很耗内存, ClientDataSet.Data := CDS;后内存耗用急剧增加,52M大小的CDS,导入TClientDataSet内存耗用增加650M左右。


上面用途中,TClientDataSet通常作为数据中转组件,不增删改数据。
有哪位高手知道,有啥现成的组件能载入大数据量CDS又不出错?
占用内存少、高效更好。

或者有其他处理办法?
----------------------------------------------
-
作者:
男 sspeak (sspeak) ★☆☆☆☆ -
盒子活跃会员
2016/12/1 1:17:36
1楼: 试试 TFDDataSet.SaveToStream/LoadFromStream
----------------------------------------------
-
作者:
男 sspeak (sspeak) ★☆☆☆☆ -
盒子活跃会员
2016/12/1 2:34:02
2楼: 另外,可参考:
http://www.cnblogs.com/hnxxcxg/p/5663372.html
http://blog.csdn.net/xieyunc/article/details/48350531
TFDMemTable比ClientDataset好用多了,没有这些古怪的问题。
----------------------------------------------
-
作者:
男 grjs_2004 (grjsITname) ★☆☆☆☆ -
盒子活跃会员
2016/12/1 8:06:41
3楼: 很显然,什么都有极限。解决办法自然是采用分页。一般用户不会一次性看完所有的数据,显示器屏幕不可能无限大。
----------------------------------------------
Everyone will to do best!
作者:
男 yuzhenguo0 (金远见) ▲▲▲▲▲ -
普通会员
2016/12/1 8:29:12
4楼: 分段给被
----------------------------------------------
学DELPHI http://www.studydelphi.com
作者:
男 luwakin (luwakin) ★☆☆☆☆ -
普通会员
2016/12/1 9:09:40
5楼: 53M,是百万级别的数据了吧。
整个我觉得和clientdataset没什么关系,delphi要解包然后再载入cds,肯定慢,而且显示这么多数据,也没什么意义吧
像你这种业务情况,一般是服务端用adodataset将数据savetofile并压缩,可以缩小到5M,然后客户端再用adodataset解压读入

用adodataset效率是很高的
----------------------------------------------
-
作者:
男 huashi86 (longwe) ★☆☆☆☆ -
普通会员
2016/12/1 9:23:35
6楼: clientdataset的日志关了 再看下会报错不 还有内存增加的问题
Cds.LogChanges:=False;
----------------------------------------------
-
作者:
男 pp0123 (pp0123) ★☆☆☆☆ -
普通会员
2016/12/1 9:31:02
6楼: clientdataset 其实是一份 text file. 慢是必然的。原概念应不会想像这么大。如果你真要三层式,那有两个方法提议。

一是避开 clientdataset 而载入 array / stringlist 之类.

二是把这一层的运作搬上 ramdisk.

当然你必需有相当记忆体, 16GB 配 64bits Windows, 分配 8G 至 10G 給ramdisk, 把 Windows 的暂存快取也搬上 ramdisk . 这就是国外专业的设计.
----------------------------------------------
-
作者:
男 kylix2008 (kylix2008) ★☆☆☆☆ -
普通会员
2016/12/1 11:27:48
7楼: 谢谢各位以上的建议。
说明一下,其他地方都没问题,是在将大数据包读入TClientDataset时提示内存不足。
 即这一句:ClientDataSet.Data := CDS
或者这句:ClientDataSet.LoadFromFile(filename)

赋值速度很快。6楼误会意思了。是内存不足。

CDS包53M(未压缩时,即使压缩了,赋给ClientDataSet也需要解压缩)大约有15万条记录,并不多,下载这么多是为了给各个客户端自行再次处理用的(筛选、汇总、过滤、合并),可能每个客户端需要处理的字段数、记录数、数据范围都不一样,因此有此需要。

下载那么大数据,不光是为了看的,还为了再处理数据。客户端程序有数据再处理功能。一次下载,多次使用。

客户端电脑较老,配置内存2G居多,4G也有,均为32位CPU,需要适应这种情况。

2楼的意见很有用,看来可替代TClientDataSet。
----------------------------------------------
-
作者:
男 huashi86 (longwe) ★☆☆☆☆ -
普通会员
2016/12/1 14:05:34
8楼: 我的意思是说ClientDataSet增加记录时,changelog占用了很大的内存,而且默认是开起来的,给他赋值data之前,先关闭的话,应该不会再有内存不足的问题。

随机生成了3个字段的100万行数据,关闭不关闭LogChanges,差很多的。
没有你具体的data数据,所以你试试。
----------------------------------------------
-
作者:
男 vmao (毛小毛) ★☆☆☆☆ -
盒子活跃会员
2016/12/1 16:44:55
9楼: 刚才用Delphi XE测试了一下,确实如楼主所说,对于大数据读取,ClientDataSet很耗内存(实际存成二进制文件并不大50M)。直接赋值Data,changelog参数没有影响的,除非是一行一样新增。

这样就纠结了,三层应用ClientDataSet是核心组件了,不用ClientDataSet用啥呢?
----------------------------------------------
-
作者:
男 earthsbest (全能中间件) ▲▲▲▲△ -
普通会员
2016/12/1 17:30:00
10楼: 二楼已经说了,TFDMemTable比ClientDataset好用多了,没有这些古怪的问题。
----------------------------------------------
Delphi4Linux Delphi三层/FireDAC 技术群:734515869 http://www.cnblogs.com/rtcmw
作者:
男 earthsbest (全能中间件) ▲▲▲▲△ -
普通会员
2016/12/1 18:34:47
11楼: 我测试用TFDMemTable加载40万条数据共74M,占用内存大约280M
----------------------------------------------
Delphi4Linux Delphi三层/FireDAC 技术群:734515869 http://www.cnblogs.com/rtcmw
作者:
男 pp0123 (pp0123) ★☆☆☆☆ -
普通会员
2016/12/1 22:46:34
12楼: kylix2008, 我是指出 ClientDataset 本身其实是文字档, 那是除了读写很需时, 资料转换成文字档也使耗内存数以倍数增长. 你不避开 ClientDataset, 就该把内存倍增, 连系统都搬上内存当然更好. 当然些方法皆采纳才是正路. Memtable 也是避开 ClientDataset 的内存方法, 但直接用 array 等方式比 Memtable 更省内存. 总言之就是那些方向. 必需使用少记忆的电脑, 那就改码用别的记存方法. 你没有其他选择.
----------------------------------------------
-
作者:
男 wk_knife (wk_knife) ★☆☆☆☆ -
盒子活跃会员
2016/12/2 8:55:30
13楼: >>下载这么多是为了给各个客户端自行再次处理用的(筛选、汇总、过滤、合并),可能每个客户端需要处理的字段数、记录数、数据范围都不一样,因此有此需要。

难道这个(筛选、汇总、过滤、合并)不是用户借你的代码实现(他总不会去数格子吧?)或ClientDataset的功能实现?难道你的或Clientdataset的实现一定能比Oracle实现的更高效?
所以还是直接把用户操作转成SQL在oracle上执行效果最好。
如果需要,单独给一个用户分页滚记录的窗口,然后再给用户一个获取分组统计结果的窗口。

假设全表排序,你肯定不能拿grid自带的功能排序,你要重新发个sql获取新排序后的分页数据。

假设我要拿所有这些数据作图,要显示所有数据,我也基本可以分几个SQL获取数据,每类(/个)字段的数据一个clientdataset,一个服务器的表对应n多客户端dataset。
----------------------------------------------
-
作者:
男 vmao (毛小毛) ★☆☆☆☆ -
盒子活跃会员
2016/12/2 11:09:05
14楼: 分页是程序员一厢情愿的做法,或者说是不得不妥协的产物。用户当然希望一眼就看到所有的数据,既快又全,没什么不好。特别是一些要做分析的数据,不是每个需求程序员都能提前预料到做好报表的,有些综合性功能可能一年只用到一次,甚至是老板开个会就要的随机不可预料的需求。大数据导出还是需要的。

另外还有一些需求比如我们公司的排产,希望一些有规律的单子(按客户,交货期)什么得排在一起,结果分页导致了她无法确定是否按她的要求排了,结果排完了一看,他妈的还有数据在第二页上,导致排产错误。那么有人说了,把分页放大,问题是放得再大也可能有跨页的,导致单据无法排在一起。这种就是一种典型的无法用分页的场合。(行和行之间有某种偶合需求的时候)

我们公司的订单,我按月分页,一年10万票订单左右,年底的时候各个部门的人是出统计报表的高峰,让他们一个月一导出都嫌麻烦。有的时候领导要做三年来的对比。分页实际是损失用户体验为前提的。不管你愿意还是不愿意。
----------------------------------------------
-
作者:
男 vmao (毛小毛) ★☆☆☆☆ -
盒子活跃会员
2016/12/2 11:25:43
15楼: 这个FireDac我看了一下,设计很像.net,用adapter离线填充数据的。

但是我很需要的一个传统datasnap,ClientDataSet的fetchondemand,packageRecord的按需求自动提取数据包的好像功能没有哦。有谁知道怎么用的?
----------------------------------------------
-
作者:
男 ghs_79 (ghs) ★☆☆☆☆ -
盒子活跃会员
2016/12/2 14:03:48
16楼: 如果大数据是客户再加工的话(需要导出Excel等),可以在服务器端生成文件,然后HTTP、FTP传送。
----------------------------------------------
Delphi爱好者。
作者:
男 sspeak (sspeak) ★☆☆☆☆ -
盒子活跃会员
2016/12/2 22:02:22
17楼: @vmao (毛小毛)
这个,TFDDataSet.FetchOptions。
还有,参见help中的 Setting Options (FireDAC)。
----------------------------------------------
-
作者:
男 kylix2008 (kylix2008) ★☆☆☆☆ -
普通会员
2016/12/3 14:09:03
18楼: 对8楼抱歉哈,我在7楼说“6楼误会意思了”,没看到有两个6楼。

14楼的意见符合我的实际,确实需要将需要的数据一次性导到客户端分析(为啥这样做的原因不细说了)。

TClientDataSet可以直接赋值TDataSetProvider.data,data的数据是二进制的,比其它格式小,便于从服务端下载,我就想找个可以直接赋值Data的组件来替代。

我用的unidac直连的Oracle,没用fireDAC。
TUniQuery.SaveToXML(Destination: TStream)可以保存数据,但unidac各组件都没有对应的LoadFromXML函数。
TDataSetProvider.data可以赋值给TClientDataset.Data, 但TFDMemTable不能接收TDataSetProvider.data格式数据。

用TFDMemTable替代TClientDataset,需要改动程序的地方比较多。

midas的数据包TDataSetProvider.data,是不是只有TClientDataset才能直接接受?

客户端有很多个,机器配置有高有低,且老板不愿升级老机器。

谢谢各位高手!
----------------------------------------------
-
作者:
男 sczhyq (旺财) ★☆☆☆☆ -
普通会员
2016/12/4 15:30:58
19楼: 可以试试我的 IndyDB 组件

http://download.csdn.net/detail/sczyq/9501063

了解一下并无害处
----------------------------------------------
我84砖家
作者:
男 ccxpts (渔夫) ★☆☆☆☆ -
普通会员
2016/12/4 16:42:42
20楼: 可以考虑分页查询
每一次查询返回2000条
cds.append := query('select * from table limit offset,2000);
offset := offser + 2000
这样查询大数据时多点几次 nextpage就可以了
----------------------------------------------
-
作者:
男 huashi86 (longwe) ★☆☆☆☆ -
普通会员
2016/12/5 11:17:01
21楼: DataSetProvider 跟TClientdataset是配套的 没道理DataSetProvider 读得OK而TClientdataset不行。 当CDS大于53M时,你试试TClientdataset的SetProvider,看下会不会还是内存不足。
----------------------------------------------
-
作者:
男 kylix2008 (kylix2008) ★☆☆☆☆ -
普通会员
2016/12/9 18:47:56
22楼: to 21楼:

CDS := DataSetProvider.Data; 
DataSetProvider读出CDS时没有用到TClientdataset。

TClientdataset很耗内存,ClientDataSet.Data := CDS时出现内存不足。也许是TClientdataset附加了很多东西增加内存占用。

因为我只需要TClientdataset有TDataSet的基本功能,想找个TClientdataset的简化版,或者找替代控件,可以直接接收CDS数据。


实在不行,只好自己精简TClientdataset。

ClientDataSet.Data := CDS赋值太快了,有人比较过,比很多数据集控件快。我测试了一下,比FDMemTable快得多。

参见Delphi内存表控件性能对比 http://blog.csdn.net/shixueli/article/details/7765783
----------------------------------------------
-
作者:
男 xingzx (xingzx) ★☆☆☆☆ -
普通会员
2016/12/9 18:57:51
23楼: 我也遇到这个问题。

好像clientdataset里面的都是用的olevariant对象,所以很占内存。

没找到解决方法
----------------------------------------------
-
作者:
男 kylix2008 (kylix2008) ★☆☆☆☆ -
普通会员
2016/12/9 19:10:24
24楼: 高人做的内存表性能测试,LoadfromFile,最快的是TClientDataSet,比FDMemTable快了近10倍。
此帖子包含附件:
PNG 图像
大小:41.4K
----------------------------------------------
-
作者:
男 kylix2008 (kylix2008) ★☆☆☆☆ -
普通会员
2016/12/9 19:26:01
25楼: 上面LoadfromFile均是载入内存虚拟盘上的文件,最大限度减少硬盘影响。
从数据文件尺寸上,TClientDataSet、SQLMemTable最小。
此帖子包含附件:
PNG 图像
大小:13.6K
----------------------------------------------
-
作者:
男 earthsbest (全能中间件) ▲▲▲▲△ -
普通会员
2016/12/9 21:25:06
26楼: 最新版的10.1 berlin up2 LoadfromFile,FDMemTable和TClientDataSet的差距很小了,LoadFromStream FDMemTable 已经超过 TClientDataSet了。
此帖子包含附件:
PNG 图像
大小:63.6K
----------------------------------------------
Delphi4Linux Delphi三层/FireDAC 技术群:734515869 http://www.cnblogs.com/rtcmw
作者:
男 kylix2008 (kylix2008) ★☆☆☆☆ -
普通会员
2016/12/10 19:27:32
27楼: 26楼:
能否把你的测试程序共享一下?
----------------------------------------------
-
作者:
男 hnxxcxg (咏南中间件) ★☆☆☆☆ -
盒子活跃会员
2016/12/20 10:58:39
28楼: FDMemTable代表的是现在和未来,ClientDataSet代表的是过去。
----------------------------------------------
中间件QQ群: 92449782 博客: http://www.cnblogs.com/hnxxcxg/
作者:
男 earthsbest (全能中间件) ▲▲▲▲△ -
普通会员
2016/12/28 10:59:38
29楼: @27楼,已上传
此帖子包含附件:earthsbest_20161228105935.zip 大小:2.81M
----------------------------------------------
Delphi4Linux Delphi三层/FireDAC 技术群:734515869 http://www.cnblogs.com/rtcmw
作者:
男 kylix2008 (kylix2008) ★☆☆☆☆ -
普通会员
2016/12/29 20:24:14
30楼: @29楼:  恕我孤陋寡闻,earthsbest_20161228105935.zip中TIdMemDataSet是啥控件?哪个组件里面的?
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行160.1563毫秒 RSS