1

次のように、従業員レコードのインポートを実行するループ (ここに要約) があります。

var cts2005 = new Cts2005Entities();
IEmployeeRepository repository = new EmployeeRepository();

foreach (var c in cts2005.Candidates)
{
    var e = new Employee();

    e.RefNum = c.CA_EMP_ID;
    e.TitleId = GetTitleId(c.TITLE);
    e.Initials = c.CA_INITIALS;
    e.Surname = c.CA_SURNAME;

    repository.Insert(e);
}

実際にはさらにいくつかのフィールドがあり、GetTitleId(c.TITLE) 上記のように合計 9 つのルックアップがあります。これらのコードはすべて次のようになります。

private List<Title> _titles;
private Guid GetTitleId(string titleName)
{
    ITitleRepository repository = new TitleRepository();
    if (_titles == null)
    {
        _titles = repository.ListAll().ToList();
    }
    var title = _titles.FirstOrDefault(t => String.Compare(t.Name, titleName, StringComparison.OrdinalIgnoreCase) == 0);
    if (title == null)
    {
        title = new Title { Name = titleName };
        repository.Insert(title);
        _titles.Add(title);
    }
    return title.Id;
}

エンティティ タイプが異なることを除いて、すべてrepository.Insert()の呼び出しは次のようになります。

public void Insert(Employee entity)
{
    CurrentDbContext.Employees.Add(entity);
    CurrentDbContext.SaveChanges();
}

そして、すべての PK は Guid です。これは小さな問題かもしれませんが、このような小さなボリュームでこれほど大きな効果があるとは思っていませんでした。

このルーチンのチューニングや最適化はまだ行っていません。これは私の小さなテスト データベース用であったためです。終わりに向かって、この処理は 1 レコードあたり約 1 秒まで遅くなり、非常に悲惨です。チューニングなしでは高速は期待できませんでしたが、それほど低速ではありませんでした。

ここで私の方法に明らかに何か間違っていることはありますか?

4

2 に答える 2

1

上記のmarc_sからのコメントのおかげで、SaveChanges500挿入ごとにのみ呼び出すようにルーチンを変更し、速度が約500%向上しました。

于 2012-07-10T16:15:10.413 に答える
1

GetTitleId はデータベースからすべてのタイトルを一度アプリケーションに取り込みますが、「候補」ごとにすべてのタイトルを線形検索します。それはおそらく非常に高価です。でクライアント側のハッシュテーブルを使用しますStringComparer.OrdinalIgnoreCase

また、アプリケーションをプロファイリングしてみませんか? それに負荷をかけ、デバッガーで 10 回ブレークを押します。ほとんどの場合、どこで停止しますか? これがホットスポットです。

于 2012-05-26T12:07:18.140 に答える