如何提高三层结构中的数据查询速度? (100分)

  • 主题发起人 主题发起人 特尔斐
  • 开始时间 开始时间

特尔斐

Unregistered / Unconfirmed
GUEST, unregistred user!
系统架构:
GUI客户端/COM+应用服务器/MS SQL SERVER2000数据库
问题起因:
当客户端需要从服务器取得大数据集到本地时(比如离线业务),通过TDataSetProvider返回这种数据集会使用系统慢如蜗牛。如果直接将ADO数据集返回到客户端将会快许多倍!
目前解决办法:
通过ADO返回结果集。(附测试代码及数据)
存在问题:
  1、如何将ADO数据集不通过文件中转而直接存入流?
2、有没有更好的提高MIDAS处理大数据集的方法?
(不要说分段读取,有时需要一次性返回整个数据集)
终极解决方案:
还望各位大侠广施援手!
具体测试数据如下:

用ADO通过文件中转返回TADODataSet记录集
记录数:7268(64个字段)
平均耗时:2466ms

用MIDAS返回TClientDataSet记录集
记录数:同上
平均耗时:8545ms
结论:用ADO的速度是MIDAS的3.46倍
且随着记录数增加,其差距还在扩大
(如果ADO不通过文件中转应会更快)

测试代码如下(下面两个过程是应用服务器上的):
{用ADO通过文件返回记录集}
function TChainGSPRDM.GetDataSet(iClientID: Integer;
const SQLText: WideString): OleVariant;
var
adsObj: TADODataSet;
sFile: string;
M: TMemoryStream;
function TempFileName: string;
var
p: array[0..MAX_PATH - 1] of char;
begin
GetTempPath(MAX_PATH, p);
Result := p + IntToStr(GetTickCount) + '.~tmp';
end;

begin
Result := Null;
InitByClient(iClientID);
adsObj := TADODataSet.Create(nil);
M := TMemoryStream.Create;
try
adsObj.Connection := adoConn;
adsObj.CommandText := SQLText;
adsObj.Open;
if adsObj.IsEmpty then
Exit;
sFile := TempFileName;
adsObj.SaveToFile(sFile);
//使用文件中转,牺牲了一些效率
adsObj.Close;
M.LoadFromFile(sFile);
StreamToVariant(M, Result);
DeleteFile(sFile);
finally
SetAbort;
adsObj.Free;
M.Free;
end;
end;

{通过MIDAS返回记录集}
function TChainGSPRDM.GetDataSetEx(iClientID: Integer;
const SQLText: WideString): OleVariant;
var
adsObj: TADODataSet;
dspObj: TDataSetProvider;
begin
Result := Null;
InitByClient(iClientID);
adsObj := TADODataSet.Create(nil);
dspObj := TDataSetProvider.Create(nil);
try
adsObj.Connection := adoConn;
adsObj.CommandText := SQLText;
dspObj.DataSet := adsObj;
adsObj.Open;
if adsObj.IsEmpty then
Exit;
Result := dspObj.Data;
//从ADO数据集到DataSetProvider.Data的转换最耗时间
adsObj.Close;
finally
SetAbort;
adsObj.Free;
dspObj.Free;
end;
end;

哪位大侠帮忙解决这个问题,300分奉上!
 
1、如何将ADO数据集不通过文件中转而直接存入流?
好象没办法,ADO没有提供此接口方法。
2、有没有更好的提高MIDAS处理大数据集的方法?
(不要说分段读取,有时需要一次性返回整个数据集)
对于大数据集,我一般采用本地库与远程库同步的模式,只更新改动过的。避免返回整个数据集。
 
1、原来ADO有提供IStream接口,只是还没有用成功。想看看哪位有用过的。
2、我主要是要从服务器一次取回大数据集,暂不考虑更新回去。
 
我看了一下DELPHI中的ADO的源文件,没有ISTREAM接口呀,你在哪儿找到的?
 
下面是微软的帮助文件上找到的:
将 Recordset 保存在文件或 Stream 对象中。
语法
recordset.Save Destination, PersistFormat
参数
Destination 可选。Variant,表示保存 Recordset 的文件的完整路径名,或者表示对 Stream 对象的引用。
PersistFormat 可选。PersistFormatEnum 值,指定 Recordset 的保存格式(XML 或 ADTG)。默认值为 adPersistADTG。
 
第一个问题已经解决!
请高手们回答一下第二个问题,谢谢!
 
现在改为不通过文件中转,而是将ADODataSet直接转为TMemoryStream并压缩后回传,将速度从原来的2466毫秒提高到了2000毫秒!基本上可以接受了。
这个转换过程对于高手们可能很简单,但我却搞了差不多三个小时!无奈,高手们都不愿帮忙。[:(]
但是ADO的DataSet转成流后体积很大(不压缩之前),同样的数据作为ClientDataSet回传只有400K,而作为ADODataSet回传则有1.3M多。
 
李维有一本分布式多层应用系统的书,看一看可能有启发。
 
to Kinki:老大,不要动不动就叫人看李维的书好吗?
 
你问题1是如何做的,贴出来共享一下行吗?[:)]
 
特尔斐vcup
说的对
 
我没有权利发言,在此借宝地一用
我用Delhi6 写的一个组件,在Delphi中我定义了一个接口函数
函数原形如下:
function ExceSqlC(Str: OleVariant): OLE_CANCELBOOL;
stdcall;
function FieldC(N: Int64): OleVariant;
stdcall;

而我在VB中引入 组件,调用function ExceSqlC 无误,而调用
Fieldc 函数,“提示函数标记为受限制的,或使用了 Visual Basic 不支持的类型”
该如何改写COM组件呢,高手指点迷津
 
有没有考虑直接用_Recordset传输
要知道_Recordset也是Com对象,可以直接传输的
也可以考虑用客户端用一个线程读数据
 
自己解决了问题却要不回分数,算了,大家发财吧。
 
后退
顶部