我已经存储30000个SimpleObjects在我的数据库:

class SimpleObject
{
    public int Id { get; set; }
} 

我希望运行查找所有SimpleObjects与任何指定的ID的上DB4O的查询:

public IEnumerable<SimpleObject> GetMatches(int[] matchingIds)
{
     // OH NOOOOOOES! This activates all 30,000 SimpleObjects. TOO SLOW!
     var query = from SimpleObject simple in db
                 join id in matchingIds on simple.Id equals id
                 select simple;
     return query.ToArray();
}  

我怎样写这个查询,以便DB4O不激活共有30,000对象?

有帮助吗?

解决方案

如果您尝试运行使用LINQ它会运行未优化(这意味着db4o的打算检索类型SimpleObject的所有对象,并委托其余的LINQ to对象)这个查询

在最好的办法是跑N次查询(因为id字段建立索引,每个查询应该跑得快)和“马克·霍尔”的建议汇总结果。

您甚至可以使用LINQ这个(类似)

IList<SimpleObject> objs = new List<SimpleObject>();
foreach(var tbf in ids)
{
     var result = from SimpleObject o in db()
               where o.Id = tbf
                  select o;

     if (result.Count == 1)
     {
        objs.Add(result[0]);
     }
}

最佳

其他提示

我不是这方面的专家,它可能是件好事张贴关于它的DB4O论坛,但我想我有一个解决办法。它包括不使用LINQ和使用SODA。

这就是我所做的。我创建了一个快速的项目填充根据您的文章的定义与30000 SimpleObject数据库。然后我写了一个查询来获取所有SimpleObjects从数据库中:

var simpleObjects = db.Query<SimpleObject>(typeof(SimpleObject));

当我缠它秒表,该运行时间约740毫秒。然后我用你的代码搜索0和2999之间的100张随机数的反应是772毫秒,所以基于这个数字,我假定它是拉动所有对象从数据库中。我不知道如何验证,但后来我觉得我的表现证明了这一点。

余然后去低。从我的理解从DB4O队LINQ提供程序只是做一个翻译成了SODA。所以我想,我会写一个SODA查询进行测试,以及我发现的是,使用SODA对一个属性是不好的性能,因为它花了19902毫秒来执行。下面是代码:

private SimpleObject[] GetSimpleObjectUsingSodaAgainstAProperty(int[] matchingIds, IObjectContainer db)
{
    SimpleObject[] returnValue = new SimpleObject[matchingIds.Length];

    for (int counter = 0; counter < matchingIds.Length; counter++)
    {
        var query = db.Query();
        query.Constrain(typeof(SimpleObject));
        query.Descend("Id").Constrain(matchingIds[counter]);
        IObjectSet queryResult = query.Execute();
        if (queryResult.Count == 1)
            returnValue[counter] = (SimpleObject)queryResult[0];
    }

    return returnValue;
}

于是想为什么会这样不好,我决定不使用自动实现的属性,并将其定义我自己,因为属性实际上是方法,而不是值:

public class SimpleObject
{
    private int _id;

    public int Id { 
        get
        { return _id; }
        set
        { _id = value; }
    }
}

我然后重写,而不是使用该属性的_id私有字段的查询。该演出是在约91毫秒好得多。下面是代码:

private SimpleObject[] GetSimpleObjectUsingSodaAgainstAField(int[] matchingIds, IObjectContainer db)
{
    SimpleObject[] returnValue = new SimpleObject[matchingIds.Length];

    for (int counter = 0; counter < matchingIds.Length; counter++)
    {
        var query = db.Query();
        query.Constrain(typeof(SimpleObject));
        query.Descend("_id").Constrain(matchingIds[counter]);
        IObjectSet queryResult = query.Execute();
        if (queryResult.Count == 1)
            returnValue[counter] = (SimpleObject)queryResult[0];
    }

    return returnValue;
}

只是为了确保它是不是侥幸,我跑了试运行多次,收到了类似的结果。然后我加入另一个60000条记录为总共90000,这是的性能差异:

GetAll: 2450 ms
GetWithOriginalCode: 2694 ms
GetWithSODAandProperty: 75373 ms
GetWithSODAandField: 77 ms

希望有所帮助。我知道,它并没有真正解释为什么,但是这可能与如何帮助。也为SODA字段查询的代码不会很难换行到更通用的。

我没有做太多使用db4o LINQ。但是你可以使用DiagnosticToConsole(或ToTrace),并把它添加到IConfiguration.Diagnostic()的addListener。这会告诉你,如果在查询优化。

您不给很多细节,但是是SimpleObject Id属性索引?

一旦诊断被打开,你可以尝试像这样的查询...

from SimpleObject simple in db
where matchingIds.Contains(simple.Id)
select simple

看看,给你一个不同的查询计划。

您可以“建”动态LINQ查询。例如,该API可以是这样的:

第一个参数:它告诉您搜索哪个属性上的表达 其他参数:该ID或任何你正在寻找

 var result1 = db.ObjectByID((SimpleObject t) => t.Id, 42, 77);
 var result2 = db.ObjectByID((SimpleObject t) => t.Id, myIDList);
 var result3 = db.ObjectByID((OtherObject t) => t.Name, "gamlerhart","db4o");

的实施建立一个动态查询是这样的:

var result = from SimpleObject t 
  where t.Id = 42 || t.Id==77 ... t.Id == N
  select t

由于一切都与结合或可以直接在索引进行评估。它不需要激活。实施例的实现:

public static class ContainerExtensions{

public static IDb4oLinqQuery<TObjectType> ObjectByID<TObjectType, TIdType>(this IObjectContainer db,
Expression<Func<TObjectType, TIdType>> idPath,
params TIdType[] ids)
{
  if(0==ids.Length)
  {
       return db.Cast<TObjectType>().Where(o=>false);
  }
  var orCondition = BuildOrChain(ids, idPath);
  var whereClause = Expression.Lambda(orCondition, idPath.Parameters.ToArray());
  return db.Cast<TObjectType>().Where((Expression<Func<TObjectType, bool>>) whereClause);
}

private static BinaryExpression BuildOrChain<TIdType, TObjectType>(TIdType[] ids,     Expression<Func<TObjectType, TIdType>> idPath)
{
  var body = idPath.Body;
  var currentExpression = Expression.Equal(body, Expression.Constant(ids.First()));
  foreach (var id in ids.Skip(1))
  {
    currentExpression = Expression.OrElse(currentExpression, Expression.Equal(body,     Expression.Constant(id)));
  }
return currentExpression;
    }

}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top