Frage

ich 30.000 SimpleObjects in meiner Datenbank gespeichert haben:

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

Ich möchte eine Abfrage auf DB4O auszuführen, die alle SimpleObjects mit einer der angegebenen IDs findet:

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();
}  

Wie schreibe ich diese Abfrage, so dass DB4O alle 30.000 Objekte nicht aktivieren?

War es hilfreich?

Lösung

Wenn Sie versuchen, diese Abfrage auszuführen LINQ verwenden, es wird laufen unoptimized (das bedeutet, dass db4o alle Objekte vom Typ SimpleObject abzurufen gehen und den Rest zu LINQ zu Objekten delegieren)

Der beste Ansatz wäre n Abfragen ausführen (da das ID-Feld indiziert ist, sollte jede Abfrage schnell laufen) und die Ergebnisse zusammenfassen, wie durch „Mark Hall“ vorgeschlagen.

Sie können auch LINQ für diese (so etwas wie)

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]);
     }
}

Best

Andere Tipps

Ich bin kein Experte auf diesem, und es könnte auf den DB4O Foren darüber schreiben gut sein, aber ich glaube, ich eine Lösung. Es geht nicht mithilfe von LINQ und mit SODA.

Das ist, was ich tat. Ich habe ein schnelles Projekt, das die Datenbank mit 30000 SimpleObject auf Ihrem Post-Definition basiert auffüllt. Ich schrieb dann eine Abfrage alle SimpleObjects greifen aus der Datenbank:

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

Wenn ich eine Stoppuhr um ihn herum gewickelt, dass Lauf dauert etwa 740 Millisekunden. Früher habe ich dann den Code für eine 100-Zufallszahl zwischen 0 und 2999. Die Antwort war 772 ms suchen, so auf der Grundlage dieser Zahl, die ich angenommen habe, dass er nicht mehr all Objekte der Datenbank zieht. Ich bin nicht sicher, wie das zu überprüfen, aber später denke ich, ich beweisen es mit Leistung.

Ich ging dann niedriger. Von meinem Verständnis ist die LINQ-Provider aus dem DB4O Team gerade dabei eine Übersetzung in SODA. Deshalb dachte ich, dass ich eine SODA Abfrage schreiben würde zu testen, und was ich fand, war, dass SODA gegen eine Eigenschaft verwendet für die Leistung schlecht ist, weil es 19.902 ms nahm auszuführen. Hier ist der Code:

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;
}

Also darüber nachzudenken, warum dies so schlimm sein würde, habe ich beschlossen, eine automatisch implementierte Eigenschaft nicht zu verwenden und es mich selbst zu definieren, da Eigenschaften tatsächlich Methoden sind und nicht die Werte:

public class SimpleObject
{
    private int _id;

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

Ich schrieb dann die Abfrage den _id privaten Bereich statt der Eigenschaft zu verwenden. Die Leistung war viel besser bei etwa 91 ms. Hier ist der Code:

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;
}

Nur um sicherzugehen, dass es kein Zufall war, lief ich den Testlauf mehrmals und erhielt ähnliche Ergebnisse. Ich habe dann weitere 60.000 Datensätze für insgesamt 90.000, und das war die Performance-Unterschiede:

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

Ich hoffe, das hilft. Ich weiß, dass sie nicht wirklich erklären, warum, aber dies könnte mit der, wie helfen. Auch der Code für die Abfrage SODA Feldes wäre nicht schwer, zu wickeln mehr generisch zu sein.

Ich habe nicht viel mit db4o LINQ getan. Aber Sie können die DiagnosticToConsole (oder ToTrace) verwenden und fügen Sie es dem IConfiguration.Diagnostic (). AddListener. Dies wird Ihnen zeigen, wenn die Abfrage optimiert wird.

Sie haben nicht viele Details geben, aber ist die Id-Eigenschaft auf SimpleObject indiziert?

Wenn Diagnose eingeschaltet ist, könnten Sie die Abfrage versuchen, wie so ...

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

Sehen Sie, wenn Sie, dass eine andere Abfrage-Plan gibt.

Sie könnten ‚bauen‘ eine dynamische Linq-Abfrage. Zum Beispiel könnten die API wie folgt aussehen:

Der erste Parameter: ein Ausdruck, der auf erzählt, welche Eigenschaft Sie suchen Die anderen Parameter. Die ids oder was auch immer Sie suchen

 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");

Die Implementierung baut eine dynamische Abfrage wie folgt aus:

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

Da ist alles kombiniert mit OR das kann auf die Indizes direkt ausgewertet werden. Dabei spielt es keine Aktivierung benötigen. Beispiel-Implementationen:

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;
    }

}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top