db4oのクエリは:ID = {アレイ内の何か}を持つすべてのオブジェクトを見つけます。
質問
私は自分のデータベース30,000 SimpleObjectsを保存した。
class SimpleObject
{
public int Id { get; set; }
}
私は、指定したIDのいずれかですべてSimpleObjectsを見つけ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のは、すべての3万オブジェクトを活性化しないように、どのように私はこのクエリを書くのですか?
解決
これは、最適化されていない実行されます。
(つまり、db4oのは、タイプSimpleObjectのすべてのオブジェクトを取得し、オブジェクトにLINQに休息を委任しようとしていることを意味します)最善のアプローチは、実行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ミリ秒かかります。私はその後、応答はので、私はそれがデータベースからすべてのオブジェクトを引っ張っていると仮定しています、その番号に基づいて772ミリ秒であった0と2999の間に100個のランダムな番号を検索するようにコードを使用していました。私はそれを確認するかどうかはわかりませんが、後で私はパフォーマンスでそれを証明したと考えています。
私は、下位行きました。私の理解から、db4oのチームからのLINQプロバイダはちょうどSODAへの翻訳を行っています。したがって、私は私がテストするSODAクエリを記述することを考え出し、それが実行に19902ミリ秒を取ったので、私が見つけたプロパティに対してSODAを使用すると、パフォーマンスに悪いことをしました。ここでは、コードは次のとおりです。
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;
}
ちょうどそれがまぐれではなかったされていることを確認するために、私はテストランを数回実行し、同様の結果を受け取りました。私は、90,000の合計のために別の60,000レコードを追加し、これはパフォーマンスの違いだっます:
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;
}
}