目前,我有两个数据集。一个人拥有一组工作所需的所有文件;另一个有存在的文件。我需要缺少的要求,也就是说,第一个数据集中的文档不在第二个数据集中。 (底层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设计;请不要回应。我对此无能为力。
答案 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;