3

この質問への回答にある BatchDelete を使用しています: EF Code First Delete Batch From IQueryable<T>?

このメソッドは、IQueryable から削除句を作成するのに時間がかかりすぎているようです。具体的には、以下の IQueryable を使用して 20.000 要素を削除するには、ほぼ 2 分かかります。

context.DeleteBatch(context.SomeTable.Where(x => idList.Contains(x.Id)));

すべての時間がこの行に費やされます。

    var sql = clause.ToString();

この行はこのメソッドの一部であり、上記の元の質問にリンクされていますが、便宜上ここに貼り付けられています。

private static string GetClause<T>(DbContext context, IQueryable<T> clause) where T : class
{
    const string Snippet = "FROM [dbo].[";

    var sql = clause.ToString();
    var sqlFirstPart = sql.Substring(sql.IndexOf(Snippet, System.StringComparison.OrdinalIgnoreCase));

    sqlFirstPart = sqlFirstPart.Replace("AS [Extent1]", string.Empty);
    sqlFirstPart = sqlFirstPart.Replace("[Extent1].", string.Empty);

    return sqlFirstPart;
}

コンパイルされたクエリを作成context.SomeTable.Where(x => idList.Contains(x.Id))すると役立つと思いますが、AFAIK では、EF 5 で DbContext を使用している間はクエリをコンパイルできません。論文ではキャッシュする必要がありますが、同じ BatchDelete の 2 回目の実行で改善の兆候は見られません。

これをより速くする方法はありますか?SQL 削除ステートメントを手動で作成することは避けたいと思います。

4

3 に答える 3

2

IQueryable はキャッシュされず、評価するたびに SQL に出ます。その上で ToList() または ToArray() を実行すると、一度評価された後、キャッシュされたバージョンとしてリストを操作できます。

インターフェイスを保持したい場合は、ToList().AsQueryable() を使用すると、キャッシュされたバージョンが渡されます。

関連投稿。 IQueryable オブジェクトをキャッシュするにはどうすればよいですか?

于 2012-12-05T03:23:36.957 に答える
1

この場合、クエリにはチェックするIDのリストが含まれており、呼び出しごとにリストが変更されるため、IQueryableをキャッシュする方法はないようです。

オブジェクトを一括削除する必要があるたびにクエリを作成する際の2分間の遅延を回避する唯一の方法は、次のようにExecuteSqlCommandを使用することでした。

var list = string.Join("','", ids.Select(x => x.ToString()));
var qry = string.Format("DELETE FROM SomeTable WHERE Id IN ('{0}')", list);
context.Database.ExecuteSqlCommand(qry);

今のところ、これを答えとしてマークします。ExecuteSqlCommandに依存しない他の手法が提案された場合は、喜んで答えを変更します。

于 2013-02-19T13:29:03.397 に答える
1

OK で動作する EF パターンがあります。

投影を使用します。DBからキーのみを返します。(プロジェクションはコンテキストに追加されないため、これは非常に簡単です。次に、キーのみのスタブ POCO でコンテキストを構築し、ヒューズに火をつけます....

基本的。

 var deleteMagazine = Context.Set<DeadMeat>.Where(t=>t.IhateYou == true).Select(t=>t.THEKEY).toList

//Now instantiate a dummy POCO with KEY only for the list,
foreach ( var bullet in deleteMagazine)
{
context.Set<deadmeat>.attach(bullet);
context.set<deadmeat>.remove(bullet);
 // consider saving chnages every 1000 records .... performance, trial different values
if (magazineisEmpty)  // your counter logic here :-)
  context.SaveChanges
}
// shoot anyone still moving
context.SaveChanges

SQLサーバープロファイラーを確認してください....

于 2013-02-19T15:30:04.213 に答える