Delphi clientdataset:加快从基于另一个数据集的记录中删除记录的速度

时间:2018-08-21 15:24:45

标签: delphi delphi-2010

目前,我有两个数据集。一个人拥有一组工作所需的所有文件;另一个有存在的文件。我需要缺少的要求,也就是说,第一个数据集中的文档不在第二个数据集中。 (底层SQL数据结构中的问题阻止了不使用过于缓慢的子查询而仅查询丢失的文档)。

我试图从必需的文档数据集中删除存在的文档,因此只包含缺少的文档。

public void checkFacade(final String facadeId) throws FacadeUnavailableException {
    if (!isFacadeAvailable(facadeId)) {
        throw new FacadeUnavailableException("unavailable", facadeId);
    }
}

我没有费心禁用控件,因为两个数据集都没有任何关联的控件。

问题在于这种方法非常慢。在需要约7000个文档的情况下,此过程需要约2.25秒才能得到我的精简清单。

有没有办法以一种更有效的方式来做我想做的事情? (除了修复当前无法控制的SQL数据外)。谢谢。

添加以下几条评论: 有人建议更好的查询可以获取单个数据集,并且首先避免出现此问题:以下是实际查询: 这是所有要求的清单:

try
  with cdsAllDocs do begin
    while not eof do begin
      cdsFilter(cdsRequiredDocs, 'JobID = ' + fieldByName('JobID').AsString + ' AND ID = ' + fieldByName('PREDEFINEDDOCID').AsString);
      while cdsRequiredDocs.RecordCount > 0 do cdsRequiredDocs.Delete;
      next;
    end; // while not eof
  end; // with cdsAllDocs 
finally
  cdsFilterClear(cdsRequiredDocs);
end;

这(非常慢)获得那里的文档:

SELECT distinct
  J.JobID,
  P.PREDEFINEDDOCID as ID
FROM JOBTEMPLATECONTEXT JT
Join DEPARTMENTJOB DJ
  on DJ.jobid = JT.JobID
  and DJ.DepartmentJobFetch = "Y"
  and UPPER(DJ.DEPARTMENTJOBSTATUS) in ("ACTIVE", "PENDING")
Join Job J
  on JT.JOBID = J.JOBID
  and J.JOBFETCH = "Y"
Join TEMPLATECONTEXT T
  on T.TEMPLATECONTEXTID = JT.TEMPLATECONTEXTID
  and JT.CONTEXTDUEDATE < "Now"
join PREDEFINEDDOC P on P.PREDEFINEDDOCID = T.TEMPCONTEXTID

请不要通过告诉我用varChars来限制我所限制的值而不是枚举类型是不好的,或者表的缠结是不好的db设计;请不要回应。我对此无能为力。

2 个答案:

答案 0 :(得分:0)

不是使用过滤器,而是将每个数据集的IndexFieldNames设置为JobID。然后,您可以遍历每个数据集一次。这比数千次应用过滤器要快得多。

var
  RequiredKey: string;
  AllKey: string;
  // I'm also assuming that Fields were created on the CDS - i.e. cdsRequiredDocsJobId, etc.


cdsRequiredDocs.IndexFieldNames := 'JobID;ID'; 
cdsAllDocs.IndexFieldNames := 'JobID;PREDEFINEDDOCID';

cdsRequiredDocs.First;
cdsAllDocs.First;

while (not cdsRequiredDocs.Eof) and (not cdsAllDocs.Eof) do 
begin
  RequiredKey := cdsRequiredDocsJobId.AsString + cdsRequiredDocsId.AsString;
  AllKey := cdsAllDocsJobId.AsString + cdsAllDocsPreDefinedDocId.AsString;

  // Move through AllDocs until we find a key that is equal or greater 
  // to the one in RequiredDocs
  while AllKey < RequiredKey do
  begin
    cdsAllDocs.Next;
    AllKey := cdsAllDocsJobId.AsString + cdsAllDocsPreDefinedDocId.AsString;      
    if cdsAllDocs.Eof then  
      break;
  end;

  // If we stopped on a key that matches then we need to 
  // delete our row, otherwise we move to the next one to check
  if AllKey = RequiredKey then
  begin
    cdsRequiredDocs.Delete;
    // We will be on the next record already - unless this was the 
    // last record in the CDS, then we will move back one. This can cause an 
    // extra pass through the loop, but since we only delete when the key matches
    // it should not cause anything to be removed that should stay
  end
  else
  begin
    cdsRequiredDocs.Next;
  end;

end; // while not eof

答案 1 :(得分:0)

使用“设置范围”(需要设置索引)比应用过滤器快得多。如果知道只有一行匹配,则还可以使用GotoKey代替SetRange。

如果将FieldByName调用替换为在循环之前设置的Field对象,也可以加快处理速度,方法是将其创建为CDS的一部分,或者在循环之前将其保存。

try
  cdsRequiredDocs.IndexFieldNames := 'JobId;ID';

  with cdsAllDocs do begin
    while not eof do begin
      cdsRequiredDocs.SetRange([fieldByName('JobID').AsString, fieldByName('PREDEFINEDDOCID').AsString],
                               [fieldByName('JobID').AsString, fieldByName('PREDEFINEDDOCID').AsString]);

      while cdsRequiredDocs.RecordCount > 0 do cdsRequiredDocs.Delete;
      next;
    end; // while not eof
  end; // with cdsAllDocs 
finally
  cdsRequiredDocs.CancelRange;
end;