3

デルファイで、頻繁に検索および変更されるデータを作成および保存するための最良の方法は何でしょうか。

基本的には、既存のデータベースで電話番号を検索し、各電話番号の使用回数、最初の使用日、最後の使用日を追跡する関数を作成したいと思います。検索されているデータベースは、基本的に注文のログであり、注文に使用された電話番号が含まれています。これはSQLデータベースなど、そのようなものを簡単に照会できるもの(古いbtrieveデータベース)ではないため、この情報を取得する方法を作成する必要があります(最終的にテキストファイルに出力するため)。

電話番号、2つの日付、使用回数を含むレコードを作成し、電話番号ごとに動的配列にレコードを追加することを考えています。次に、データベース内の各レコードの配列をエントリごとに検索して、現在のレコードの電話番号がすでに配列に含まれているかどうかを確認します。次に、必要に応じてレコードを更新または作成します。

これはうまくいくように見えますが、データベースには何万ものエントリがあるため、これは最善の方法ではなく、処理が遅く非効率的な方法である可能性があります。データベースで実行できるアクションが限られていることを考えると、より良い方法はありますか?

誰かが、配列を使用するのではなく、MySQLテーブルを使用して数値を追跡し、データベースレコードごとに各数値をクエリすることを提案しました。ただし、これはさらにオーバーヘッドのようです。

お時間をいただき、誠にありがとうございます。

4

5 に答える 5

1

わかりました、これはうまく機能し、うまくスケーリングするはずのダブルパスの昔ながらの方法です(私はこのアプローチを数百万レコードのデータベースに対して一度使用しましたが、時間はかかりましたが正確な結果が得られました)。

  1. Turbo Power SysToolsをダウンロードしてインストールします。ソート エンジンは、このプロセスに非常に適しています。
  2. 電話番号の固定レコードを使用して並べ替えを作成します。これを使用して並べ替えます。
  3. レコードをループし、注文ごとに、電話番号を並べ替えに追加します。
  4. 最初の反復が完了したら、並べ替えから電話番号のポップを開始し、電話番号が最後に読み取ったものと同じ場合はカウンターをインクリメントし、そうでない場合は番号を報告してカウンターをクリアします。

このプロセスは任意の SQL データベースでも実行できますが、私の経験では、一時テーブルを管理するよりも並べ替え方法の方が高速で、同じ結果が生成されます。

編集- これは BTrieve データベースであると述べました。電話番号でキーを作成し、そのキーで並べ替えてから、このテーブルに手順 4 を適用します (pop ではなく next)。いずれにせよ、データベース内のすべてのレコードに触れてカウントを取得する必要がありますが、インデックス/並べ替えにより、意思決定プロセスが簡単になります。

たとえば、2 つのテーブルがあり、1 つは結果が格納される顧客テーブルで、もう 1 つは注文テーブルであるとします。両方を同じ電話番号で並べ替えます。次に、両方のリストの先頭でカーソルを開始し、次の疑似コードを適用します。

Count := 0;
While (CustomerTable <> eof) and (OrderTable <> eof) do
  begin
    comp = comparetext( customer.phone, order.phone );
    while (comp = 0) and (not orderTable eof) do 
      begin
        inc( Count );
        order.next;
        comp = comparetext( customer.phone, order.phone );
      end;
    if comp < 0 then
      begin
        Customer.TotalCount = count;
        save customer;
        count := 0;
        Customer.next;
      end
    else if (Comp > 0) and (not OrderTable EOF) then
      begin
        Order.Next;  // order no customer
      end;  
   end;

// handle case where end of orders reached
if (OrdersTable EOF) and (not CustomersTable EOF) then
  begin
    Customer.TotalCount = count;
    save customer;
  end;

このコードには、両方のリストを 1 回ウォークするという利点があります。両方のリストが同じようにソートされるため、ルックアップは必要ありません。必要な場合にのみ、上から下に移動してアクションを実行できます。唯一の要件は、両方のリストに共通点 (この例では電話番号) があり、両方のリストを並べ替えることができることです。

注文があって客がいない場合は扱っていません。私の仮定では、注文は顧客なしでは存在せず、カウントのためにスキップされるというものでした.

于 2009-05-05T17:10:46.420 に答える
1

集計を完全に切断された TClientDataset(cds) に登録し、ループから取得した値を更新します。Btrieve を電話番号で並べ替えることができれば、はるかに優れています。次に、CD のデータを使用してレポートを生成します。

(この方法を使用する場合は、 Andreas Hausladen のブログからMidas SpeedFixを入手することをお勧めします)。

于 2009-05-05T16:19:07.650 に答える
0

申し訳ありませんが、私の投稿を編集できませんでした(その時点では登録されていませんでした)。データベース内のすべてのレコードが繰り返されると、データは破棄されます。関数は頻繁には呼び出されません。これは基本的に、私たちがすでに持っているレコードから一定期間に人々が注文した頻度を判断する方法として使用されるため、実際には1つだけのリストを作成する必要があります。

データは、リストの作成中は永続的です。つまり、最後のデータベースレコードが読み取られるまで、検索するにはすべての電話番号が存在する必要があります。

于 2009-05-05T15:57:58.013 に答える
0

それをメモリに保持するつもりで、特別なことをしたくない場合は、TStringListを使用して、Find関数を使用できるようにすることをお勧めします。検索では、Hoareの選択またはクイックセレクト(O(n)ロケーター)を使用します。たとえば、タイプを定義します。

type
   TPhoneData = class
      private
         fPhone:string;
         fFirstCalledDate:TDateTime;
         fLastCalledDate:TDateTime;
         fCallCount:integer;
      public
         constructor Create(phone:string; firstDate, lastDate:TDateTime);
         procedure updateCallData(date:TDateTime);
         property phoneNumber:string read fPhone write fPhone;
         property firstCalledDate:TDateTime read fFirstCalledDate write fFirstCalledDate;
         property lastCalledDate:TDateTime read fLastCalledDate write fLastCalledDate;
         property callCount:integer read fCallCount write fCallCount;
      end;

{ TPhoneData }

constructor TPhoneData.Create(phone: string; firstDate, lastDate: TDateTime);
begin
fCallCount:=1;
fFirstCalledDate:=firstDate;
fLastCalledDate:=lastDate;
fPhone:=phone;
end;

procedure TPhoneData.updateCallData(date: TDateTime);
begin
inc(fCallCount);
if fFirstCalledDate<date then fFirstCalledDate:=date;
if date>fLastCalledDate then fLastCalledDate:=date;
end;

そしてそれを記入し、それについて報告します:

procedure TForm1.btnSortExampleClick(Sender: TObject);
const phoneSeed:array[0..9] of string = ('111-111-1111','222-222-2222','333-333-3333','444-444-4444','555-555-5555','666-666-6666','777-777-7777','888-888-8888','999-999-9999','000-000-0000');

var TSL:TStringList;
    TPD:TPhoneData;
    i,index:integer;
    phone:string;
begin
randseed;
TSL:=TStringList.Create;
TSL.Sorted:=true;
for i := 0 to 100 do
   begin
   phone:=phoneSeed[random(9)];
   if TSL.Find(phone, index) then
      TPhoneData(TSL.Objects[index]).updateCallData(now-random(100))
   else
      TSL.AddObject(phone,TPhoneData.Create(phone,now,now));
   end;
for i := 0 to 9 do
   begin
   if TSL.Find(phoneSeed[i], index) then
      begin
      TPD:=TPhoneData(TSL.Objects[index]);
      ShowMessage(Format('Phone # %s, first called %s, last called %s, num calls %d', [TPD.PhoneNumber, FormatDateTime('mm-dd-yyyy',TPD.firstCalledDate), FormatDateTime('mm-dd-yyyy',TPD.lastCalledDate), TPD.callCount]));
      end;
   end;
end;
于 2009-05-05T16:40:36.150 に答える
0

TStringList の代わりに、 (sf.net 上の) DeCAL のDMap を使用してアイテムをメモリに格納することをお勧めします。電話をキーとして指定し、残りのレコードを含む Record/Class 構造を保存できます。

したがって、 Record クラスは次のようになります。


  TPhoneData = class
    number: string;
    access_count: integer;
    added: TDateTime.
     ...
  end;

次にコードで:


  procedure TSomeClass.RegisterPhone(number, phoneData);
  begin
    //FStore created in Constructor as FStore := DMap.Create;
    FStore.putPair([number, phoneData])
  end;
  ...
  procedure TSoemClass.GetPhoneAndIncrement(number);
  var
    Iter: DIterator;
    lPhoneData: TPhoneData;
  begin
    Iter := FStore.locate([number]);
    if atEnd(Iter) then
      raise Exception.CreateFmt('Number %s not found',[number])
    else
    begin
      lPhoneData := GetObject(Iter) as TPhoneData;
      lPhoneData.access_count = lPhoneData.access_count + 1;
      //no need to save back to FStore as it holds a pointer to lPhoneData
    end;
  end;

DMap は赤/黒のツリーを実装しているため、データ構造はキーを無料でソートします。同じ効果と (ほぼ間違いなく) 速度の向上のために DHashMap を使用することもできます。

DeCAL は、私のお気に入りのデータ構造ライブラリの 1 つであり、メモリ内ストレージ操作を行うすべての人に一見をお勧めします。

それが役立つことを願っています

于 2009-05-05T22:12:14.977 に答える