谁能帮我把这段代码优化一下,以提高效率?
var
i,j:integer;
begin 
ADODataSetFenbu.DisableControls;  
for j:=1 to 30 do
begin
  ADODataSetFenbu.first;
  i:=0;
   while not ADODataSetFenbu.Eof do
   begin
   if  ADODataSetFenbu.FieldByName('No'+inttostr(j)).asstring = '' then
       begin
       i:=i+1;
       ADODataSetFenbu.edit;
       ADODataSetFenbu.FieldByName('No'+inttostr(j)).asstring:=inttostr(i);
       ADODataSetFenbu.post;
       end
   else
       begin
       i:=0;
       end;
       ADODataSetFenbu.next;
   end;
end;
ADODataSetFenbu.EnableControls;
end;

解决方案 »

  1.   

    如果对逐条对每个字段赋值,没得 优化,除非你可以吧他改造成insert语句
      

  2.   


    //只能这样,使用一次遍历,减小29次 遍历var
    i:integer;
    aa : array[1..30] of byte ;
    begin 
    FillChar( aa,30,0);
    ADODataSetFenbu.DisableControls;  
    ADODataSetFenbu.first;
      while not ADODataSetFenbu.Eof do
      begin
       for i:=1 to 30 do
       begin
       if ADODataSetFenbu.FieldByName('No'+inttostr(i)).asstring = '' then
       begin
       Inc(aa[i]);
       ADODataSetFenbu.edit;
       ADODataSetFenbu.FieldByName('No'+inttostr(i)).asstring:=aa[i];
       ADODataSetFenbu.post;
       end;
       end;
       ADODataSetFenbu.next;
      end;
    ADODataSetFenbu.EnableControls;
    end;
      

  3.   

    用sql的语句处理,可以提高效率;
      

  4.   

    可以将ADODataSetFenbu.FieldByName('No'+inttostr(j))这个放在while循环外,用一个临时的field变量来代替,可以减少ADODataSetFenbu.FieldByName函数的调用。
      

  5.   

    如果我没理解错,就是每一列 No1..NO30 字段,从 第一个记录起到最后一个记录,为空的标识第为 n ,n=n+1 每一列不同, 所以我用一个 30 个记录的数组保存每一列计算到的位置 , 但我原有代码有 bug , 最多支持 255 个记录,现修正如下(支持 int64 个记录),你自己试试结果同你上面是否一样 , 算法的思路是大大减小数据库访问量,例如你有 10000 个记录,用你的算法,要访问 10000*30 个记录,即30万,
    而这个算法,只需 1 万次访问,记录越多,加速越快var
        i:integer;
        aa : array[1..30] of int64 ;   //原有代码用 byte, 只支持 255 个记录
    begin 
          for i:=1 to 30 do
            array[i]=0;
        ADODataSetFenbu.DisableControls;  
        ADODataSetFenbu.first;
      while not ADODataSetFenbu.Eof do
      begin
          for i:=1 to 30 do
          begin
              if ADODataSetFenbu.FieldByName('No'+inttostr(i)).asstring = '' then
              begin
                  Inc(aa[i]);
                  ADODataSetFenbu.edit;
                  ADODataSetFenbu.FieldByName('No'+inttostr(i)).asstring:=aa[i];
                  ADODataSetFenbu.post;
              end;
          end;
          ADODataSetFenbu.next;
      end;
        ADODataSetFenbu.EnableControls;
    end;
      

  6.   

    错了,不为空重新置 0, 最后修正版 , 试试这个,应该同你上面的结果一样
    var
      i:integer;
      aa : array[1..30] of int64 ; //原有代码用 byte 有bug, 只支持 255 个记录
    begin 
      for i:=1 to 30 do
      begin
        array[i]=0;
      end;
      ADODataSetFenbu.DisableControls;  
      ADODataSetFenbu.first;
      while not ADODataSetFenbu.Eof do
      begin
        for i:=1 to 30 do
        begin
          if ADODataSetFenbu.FieldByName('No'+inttostr(i)).asstring = '' then
          begin
            Inc(aa[i]);
            ADODataSetFenbu.edit;
            ADODataSetFenbu.FieldByName('No'+inttostr(i)).asstring:=aa[i];
            ADODataSetFenbu.post;
          end
          else
          begin
            aa[i]=0;
          end;
        end;
        ADODataSetFenbu.next;
      end;
      ADODataSetFenbu.EnableControls;
    end;
      

  7.   

    首先你的代码有些地方错误,下面是我在你楼上的基础上完善后的代码,但是还是达不到我的目的,我要求的是:30个字段,每个字段,每条记录,为空的就从1开始填充直到遇到不为空的数据就结束,又重新从1开始填充!!!var
      i:integer;
      aa : array[1..30] of integer ;
    begin 
      for i:=1 to 30 do
      begin
        aa[i]:=0;
      end;
      ADODataSetFenbu.DisableControls;
      ADODataSetFenbu.first;
      while not ADODataSetFenbu.Eof do
      begin
        for i:=1 to 30 do
        begin
          if ADODataSetFenbu.FieldByName('No'+inttostr(i)).asstring = '' then
          begin
            Inc(aa[i]);
            ADODataSetFenbu.edit;
            ADODataSetFenbu.FieldByName('No'+inttostr(i)).asstring:=inttostr(aa[i]);
            ADODataSetFenbu.post;
          end
          else
          begin
            aa[i]:=0;
          end;
        end;
        ADODataSetFenbu.next;
      end;
      ADODataSetFenbu.EnableControls;
    end;
      

  8.   

    楼上的有QQ吗?提供给我QQ,或加我QQ:570633255私聊这个问题,谢谢你的帮助
      

  9.   

    基本上思路是这样的:
    先从数据库取得数据集,记录下需要更新的行的主键,保存成一个列表,
    然后分N个线程根据这个列表执行更新操作
    (要用SQL语句执行更新,因为是多线程,QUERY的POST不能同时来更新多行数据)
    执行完之后,再从数据库取得更新后的数据集
    这样速度会快N倍,呵呵。。
      

  10.   

    基本上思路是这样的:
    先从数据库取得数据集,记录下需要更新的行的主键,保存成一个列表,
    然后分N个线程根据这个列表执行更新操作
    (要用SQL语句执行更新,因为是多线程,QUERY的POST不能同时来更新多行数据)
    执行完之后,再从数据库取得更新后的数据集
    这样速度会快N倍,呵呵。。
      

  11.   

    其实这种功能的实现,不能放到DELPHI中去优化,换个角度,把这个优化放到SQL语句中去。
    可以写一个存储过程,把这种数据修改后,再显示到前台界面。
      

  12.   


    我自己测试了一下,同样一个25555条的表,我更新其中一个字段
    放到主线程中用了将近一分钟,分十个线程执行的话在12~15秒之间
    效果显而易见PAS:
    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, DB, ADODB,ActiveX,SyncObjs;const
      WM_USERCOMPLETE=WM_USER+100;type
      TDataUpdateThread=class(TThread)
      private
        FConnection:TADOConnection;
        FQuery:TADOQuery;
      protected
        procedure Execute;override;
      public
        constructor Create(ASuspended:Boolean);
        destructor Destroy;override;
      end;  TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        Label1: TLabel;
        Label2: TLabel;
        ADOConnection1: TADOConnection;
        ADOQuery1: TADOQuery;
        Button3: TButton;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure Button3Click(Sender: TObject);
      private
        Complete:Boolean;
        ThreadList:TList;
        StartTime:TDateTime;
        Lock:TRTLCriticalSection;
        procedure WMUSERCOMPLETE(var message:TMessage);message WM_USERCOMPLETE;
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
    begin
      StartTime:=Now;  ADOQuery1.First;
      while Not ADOQuery1.Eof do
      begin
        ADOQuery1.Edit;
        ADOQuery1.FieldByName('IsSpam').AsBoolean:=False;
        ADOQuery1.Post;
        ADOQuery1.Next;
      end;  Label1.Caption:='单线程:开始时间:'+DateTimeToStr(StartTime)+'结束时间:'+DateTimeToStr(Now);end;procedure TForm1.Button2Click(Sender: TObject);
    var
      Thread:TDataUpdateThread;
      I: Integer;
    begin
      StartTime:=Now;
      ADOQuery1.First;
      //启动线程
      for I := 0 to 10 - 1 do
      begin
        Thread:=TDataUpdateThread(ThreadList.Items[I]);
        Thread.Resume;
      end;
    end;procedure TForm1.Button3Click(Sender: TObject);
    begin
      ADOQuery1.Close;
      ADOQuery1.SQL.Text:='Select * from tmMailList1';
      ADOQuery1.Open;
    end;procedure TForm1.FormCreate(Sender: TObject);
    var
      Thread:TDataUpdateThread;
      I: Integer;
    begin
      InitializeCriticalSection(Lock);
      Complete:=False;  ADOQuery1.Close;
      ADOQuery1.SQL.Text:='Select * from tmMailList1';
      ADOQuery1.Open;  //创建线程
      ThreadList:=TList.Create;
      for I := 0 to 10 - 1 do
      begin
        Thread:=TDataUpdateThread.Create(True);
        ThreadList.Add(Thread)
      end;
    end;procedure TForm1.FormDestroy(Sender: TObject);
    begin
      DeleteCriticalSection(Lock);
    end;procedure TForm1.WMUSERCOMPLETE(var message: TMessage);
    begin
      ADOQuery1.Close;
      ADOQuery1.Open;
      Label2.Caption:='多线程:开始时间:'+DateTimeToStr(StartTime)+'结束时间:'+DateTimeToStr(Now);
    end;{ TDataUpdateThread }constructor TDataUpdateThread.Create(ASuspended: Boolean);
    begin
      Inherited Create(ASuspended);  FConnection:=TADOConnection.Create(nil);
      FConnection.ConnectionString:='False';
      FConnection.Connected:=True;
      FQuery:=TADOQuery.Create(nil);
      FQuery.Connection:=FConnection;end;destructor TDataUpdateThread.Destroy;
    begin
      FConnection.Free;
      FQuery.Free;
      inherited;
    end;procedure TDataUpdateThread.Execute;
    var
      FID:Integer;
      First:Boolean;
    begin
      inherited;
      First:=False;
      while Not Terminated do
      begin
        while Not Form1.ADOQuery1.Eof do
        begin      EnterCriticalSection(Form1.Lock);
          if Not Form1.ADOQuery1.Eof then
          begin
            FID:=Form1.ADOQuery1.FieldByName('MID').AsInteger;
            Form1.ADOQuery1.Next;
          end
          else
          begin
            if Not Form1.Complete then
            begin
              First:=True;
              Form1.Complete:=True;
            end;
          end;
          LeaveCriticalSection(Form1.Lock);
          if Not Form1.Complete then
          begin
            FQuery.Close;
            FQuery.SQL.Text:='Update tmMailList1 set IsSpam=0 where MID='+IntToStr(FID);
            FQuery.ExecSQL;
          end;      if First then
          begin
            PostMessage(Form1.Handle,WM_USERCOMPLETE,0,0);
          end;      if Form1.Complete then
          begin
            Terminate;
          end;
        end;
      end;
    end;initialization
        CoInitialize(nil);finalization
        CoUnInitialize;end.
    DFM:object Form1: TForm1
      Left = 0
      Top = 0
      Caption = 'Form1'
      ClientHeight = 263
      ClientWidth = 483
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'Tahoma'
      Font.Style = []
      OldCreateOrder = False
      OnCreate = FormCreate
      OnDestroy = FormDestroy
      PixelsPerInch = 96
      TextHeight = 13
      object Label1: TLabel
        Left = 24
        Top = 143
        Width = 385
        Height = 13
        AutoSize = False
        Caption = 'Label1'
      end
      object Label2: TLabel
        Left = 24
        Top = 184
        Width = 385
        Height = 13
        AutoSize = False
        Caption = 'Label1'
      end
      object Button1: TButton
        Left = 72
        Top = 112
        Width = 75
        Height = 25
        Caption = #21333#32447#31243#22788#29702
        TabOrder = 0
        OnClick = Button1Click
      end
      object Button2: TButton
        Left = 288
        Top = 112
        Width = 75
        Height = 25
        Caption = #22810#32447#31243#22788#29702
        TabOrder = 1
        OnClick = Button2Click
      end
      object Button3: TButton
        Left = 200
        Top = 32
        Width = 75
        Height = 25
        Caption = 'Button3'
        TabOrder = 2
        OnClick = Button3Click
      end
      object ADOConnection1: TADOConnection
        Connected = False
        LoginPrompt = False
        Provider = 'SQLOLEDB.1'
        Left = 96
        Top = 24
      end
      object ADOQuery1: TADOQuery
        Connection = ADOConnection1
        Parameters = <>
        Left = 96
        Top = 64
      end
    end呵呵,贴上代码,随便写写。。高手请匆挑错啊。。
    开二十个线程也试了一下,也差不多十几秒。。线程数自己衡量吧。