私が仕事で構築しているアプリケーションには、100,000行以上の「People」というテーブルを持つ大規模なデータベースがあります。さらに、このテーブルのエントリには、親タイプと子タイプの2種類のデータが含まれています。各子タイプのエントリには、特別な「Child_OF」列にその親のデータベースIDがあります。
メモリ内では、両方のデータベースエントリタイプは、対応するクラス「TParent」と「TChild」で表されます。各親クラスには、フィールド「children:TList」があります。
これは、ADOを使用して、次のことを行うための最速の方法です。-親のリストを作成し、それらに子を正しく割り当てます。
私の見方では... 1)テーブルからすべての親を一括で(1つのSQLクエリで)取得し、空の子リストを含む親リストを作成することで問題を解決できます。2)すべての子をまとめて取得し、各親について、対応するデータセットから自分の子を見つけようとします。
これは、プログラムの割り当て段階で私が考えていることの例です...
procedure assignParentsTheirChildren(parentList: TList<TParent>;
ma_people: TADOTable);
var
i: Integer;
qry: TADOQuery;
aChild: TChild;
aParent: TParent;
begin
// create the query
qry := TADOQuery.Create(nil);
qry.Connection := ma_people.Connection;
// set the sql statement to fetch all children ...
qry.SQL.Clear;
qry.SQL.Add('Select * from ' + ma_people.TableName + ' WHERE ChildOF <> ' +
QuotedStr(''));
// supposedly do some optimization---
qry.CursorLocation := clUseClient; // load whole recordset in memory
qry.DisableControls;
// disable controls ensures that no dataset bound control will be updated while iterating the recordset
qry.CursorType := ctStatic; // set cursor to static
// open dataset
qry.Open;
// ***EDIT*** for completeness I add the suggestion made by Agustin Seifert below
qry.RecordSet.Fields['ChildOf'].Properties.Item['Optimize'].value := true;
for i := 0 to parentList.count - 1 do
begin
// get daddy
aParent := parentList[i];
qry.Filter := 'ChildOF = ' + QuotedStr(IntToStr(aParent.parentID));
qry.Filtered := true;
while (not qry.EOF) do
begin
aChild := TChild.Create;
getChildFromQuery(aChild, qry); // fills in the fields of TChild class...
aParent.children.Add(aChild);
qry.Next;
end;
end;
qry.Free;
end;
上記のコードの最大のボトルネックは、新しい親ごとにデータをフィルタリングしていることだと思います。seek()またはlocate / find ...を使用したより高速なやり直しはありますか?基本的に、私のデータセットは静的であり(親リストの作成時)、ネットワーク遅延は無限であると想定できます:)(つまり、最初にメモリから子から親への割り当てを行いたい)。どうもありがとう!
ところで、私はMicrosoft SQL Server2012を使用しています。
コード/ロジックを変更したくない場合は、ADOでのフィルター、検索、並べ替えの操作を最適化する方法があります。レコードセットにアクセスし、関連するフィールドを最適化します。
var
qry: TADOQuery;
rs: _Recordset;
...
begin
...
//after qry.Open;
rs := qry.Recordset;
rs.Fields['YourField'].Properties.Item['Optimize'].Value := True; //YourField = ChildOF in your case
これにより、フィールドのインデックスが作成されます。インデックスなしで多くの時間をフィルタリングするのにかかる時間と比較して、少し時間がかかります。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加