AdoDataSet1和AdoDataSet2两个数据集结构一样,主键为字段Ryid,每个库均有2000个以上记录,现要求一个最高效率的算法:比较两个数据集中的记录,如果AdoDataSet1中的记录AdoDataSet2中没有,则把这条记录添加至AdoDataSet2中。 因为数据集来源有些字段不是来自表,不能用SQL语句来比较记录来合并不同值。  
  我用传统的算法:   
  var   
      ls_ryid:string;   
      i:Integer;   
  begin   
      AdoDataSet1.First;     
      AdoDataSet2.First;     
      while   Not   AdoDataSet1.Eof   do   
          begin   
                ls_ryid:=AdoDataSet1.FieldbyName('Ryid').AsString;   
                if   Not   AdoDataSet2.Loacte(Ryid,ls_ryid,[])   then   
                AdoDataSet2.Append;   
                for   i:=0   to   AdoDataSet2.Fields.Count-1   do   
                    AdoDataSet2.Fields[i].value:=AdoDataSet1.Field[i].value;   
                AdoDataSet1.Next;   
          end;   
  end;   
   这样很慢,原因有3:
1,对AdoDataSet1进行了所有记录的循环。
2,对AdoDataSet2进行了Loacte方法
3,对字段赋值进行了逐一字段的赋值:  AdoDataSet2.Fields[i].value:=AdoDataSet1.Field[i].value;以上是问题所在,
谁能帮忙想想,有提高效率的更好方法吗?

解决方案 »

  1.   

    在记录集中处理,也只有此方法,效率肯定低下。
    有些字段不是来自表,应该也还是有间接方法采用SQL进行数据合并?
      

  2.   

    我有两个表也是比较回添,但用的是SQL处理,一个表两万条、另一个七千条,用了8分钟,速度慢4了
      

  3.   

    想到几点,看看有没有帮助:
    1。不要在遍历的过程中插入,在不改变任何内容的情况下遍历原数据集应该是很快的,这个时候使用一个TList记录下所有的书签;
    2。遍历完后不要关闭数据集,读内存中的所有书签,然后再对目标数据集进行插入;
    3。在循环开始处就用.Last读入所有目标数据集的记录,而记录没有改变的情况下,Locate的速度应该会比较快。
    以上几点纯属猜想-___-b
      

  4.   

    现在最主要的慢的地方就是       for  i:=0 to  AdoDataSet2.Fields.Count-1 do       
                 AdoDataSet2.Fields[i].value:=AdoDataSet1.Field[i].value;    
          AdoDataSet1.Next;     
    因为每次数据集的循环,都会对每个字段循环赋值。谁能想到一个方法对AdoDataSet2和AdoDataSet1之间的字段赋值的其他办法?有不有直接把AdoDataSet1当前记录整个赋给AdoDataSet2,而不是一个一个字段赋值?如果能解决这个问题,估计速度将大大提速。
      

  5.   

    楼主目前的方法不是最快的。因为它的效率是O(n~2)。下面的方法可以试验一下(因为我没试过):
    1。不要用数据集的First、NEXT,研究一下ADODATASET.RECORDSET,用它访问数据集数据效率要快。
       具体怎么用到网上找一下就知道了。
    2.可以试一下两个ADODATASET都用主键做相同索引(ADODATASET里有个INDEXFIELDNAMES属性)。
       用相同顺序互相对比。效率应该是O(n)。
      

  6.   

    楼主,你能select出来两个dataset,就不能直接select到两个临时表里?
    到了临时表里以后insert into 2 where key_field not in (select key_field from xxx表) 不就得了?
      

  7.   

    如果需要插入很多记录(即有大量非匹配记录),建议用第3个数据集作缓存,等到找出所有非匹配记录后,再统一搬到数据集2种,这样就减少了搜索的循序次数。不过你的性能关键似乎不在此,因为你的数据显得并不太多,不知道ADoDataSet是内存数据集吗,在大量数据排序或计算时,我习惯用ClientDataSet,他内存级别的的,跟物理数据库没关系的。   
      

  8.   

    简单.既然已经定义了主键,那么默认该主键的值是唯一且已排序.procedure AddAdoDataSet1toBuffer;
    begin
    //
    end;procedure PostBufferToAdoDataSet2;
    begin
    //
    end;procedure Compare2Tables;
    begin
    AdoDataSet1.First;
    AdoDataSet2.First;
    repeat
        if AdoDataSet1.FieldbyName(Ryid).AsInteger = AdoDataSet2.FieldbyName(Ryid).AsInteger then begin
           AdoDataSet1.Next;
           AdoDataSet2.Next;
        end else if AdoDataSet1.FieldbyName(Ryid).AsInteger > AdoDataSet2.FieldbyName(Ryid).AsInteger then begin
           AdoDataSet2.Next
        end else if AdoDataSet1.FieldbyName(Ryid).AsInteger < AdoDataSet2.FieldbyName(Ryid).AsInteger then begin
           AddToBuffer;
           AdoDataSet1.Next;
        end;
    until(AdoDataSet1.EOF);
    PostBufferToAdoDataSet2;
    end;两个数据集各扫描一遍.
      

  9.   

    没道理用不了SQL,肯定可以间接使用SQL进行比较
      

  10.   

    很难用SQL实现,因为其中一个数据集是从客户端通过IAppserver接口的方法传递上来的,这是来此客户端本地的ACCESS数据库,现在这个比较是在中间层的服务器上的软件里进行的。
      

  11.   

    就一关键字比较,然后将求并集的问题。关键字比较最快是使用hash方法,查看贴子:
    http://topic.csdn.net/t/20061018/21/5092570.html
    强人的做法。求并的方法就简单了,得到不存在的数据后,直接写个SQL:
    insert into table2 (field1, field2....) select field1, field2... from table1 where id in (id1, id2, id3...)这样最快了。
    还adotable1.append....,比较晕人的法子。
      

  12.   

    哦,最简单的方法是直接用SQL,开始是用楼主的思路做,才发现直接用SQL更明了。insert into table2 
      select * from table1 t1
        where not exists( select 1 from table2 where id = t1.id )
      

  13.   

    ERR0RC0DE 是正解。还是用SQL效率高