3

我正在使用在这个问题的答案中找到的 BatchDelete:EF Code First Delete Batch From IQueryable<T>?

该方法似乎浪费了太多时间从 IQueryable 构建删除子句。具体来说,使用下面的 IQueryable 删除 20.000 个元素需要将近两分钟。

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的迹象。

有没有办法让它更快?我想避免手动构建 SQL 删除语句。

4

3 回答 3

2

IQueryable 没有缓存,每次评估它时都会使用 SQL。在其上运行 ToList() 或 ToArray() 将对其进行一次评估,然后您可以将列表用作缓存版本。

如果你想保留你的接口,你可以使用 ToList().AsQueryable() ,这会传入一个缓存版本。

相关帖子。 如何缓存 IQueryable 对象?

于 2012-12-05T03:23:36.957 回答
1

在这种情况下,似乎无法缓存 IQueryable,因为查询包含要检查的 id 列表,并且每次调用都会更改列表。

我发现每次我必须批量删除对象时避免构建查询的两分钟延迟的唯一方法是使用 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

有一个 EF 模式可以正常工作。

它使用投影。仅从数据库返回密钥。(投影不会添加到上下文中,所以这非常快。然后您使用仅 KEY 存根 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 回答