DB4O Query: ابحث عن جميع الكائنات مع المعرف = {أي شيء في صفيف}

StackOverflow https://stackoverflow.com/questions/1689089

  •  18-09-2019
  •  | 
  •  

سؤال

قمت بتخزين 30،000 SimpleObjects في قاعدة البيانات الخاصة بي:

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

أريد تشغيل استعلام على DB4O الذي يجد كل SimpleObjects مع أي من المعرفات المحددة:

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 بتنشيط جميع الكائنات الثلاثين؟

هل كانت مفيدة؟

المحلول

إذا حاولت تشغيل هذا الاستعلام باستخدام LinQ، فسيتم تشغيله بشكل غير محدد (يعني أن DB4O سوف يسترجع جميع الكائنات من نوع SimpleObject وتفويض الباقي إلى LinQ إلى كائنات)

سيكون أفضل طريقة تشغيل استفسارات n (نظرا لأن حقل المعرف مفهرسا، يجب أن يعمل كل استعلام سريعا) وتجميع النتائج كما اقترح "علامة قاعة".

يمكنك حتى استخدام 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 واستخدام الصودا.

وهذا هو ما فعلته. قمت بإنشاء مشروع سريع يملأ قاعدة البيانات باستخدام 30000 SimpleObject بناء على تعريف المنشور الخاص بك. ثم كتبت استعلاما للاستيلاء على جميع SimpleObjects من قاعدة البيانات:

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

عندما اختطفت ساعة توقيت حولها، فإن هذا يعمل يستغرق حوالي 740 مللي ثانية. ثم استخدمت التعليمات البرمجية الخاصة بك للبحث عن أرقام عشوائية 100 بين 0 و 2999. كانت الاستجابة 772 مللي ثانية، واستند إلى هذا الرقم الذي أفترض أنه يسحب جميع الكائنات من قاعدة البيانات. لست متأكدا من كيفية التحقق من ذلك، ولكن في وقت لاحق أعتقد أنني أثبتت ذلك بالأداء.

ثم ذهبت أقل. من فهمي هو مزود LINQ من فريق DB4O هو مجرد القيام ترجمة إلى الصودا. لذلك أحسب أنني سأكتب استعلام صودا لاختبار، وما وجدته هو أن استخدام الصودا ضد خاصية أمر سيء للأداء لأنه استغرق MS 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;
}

فقط للتأكد من أنها ليست حظية، ركضت الاختبار تشغيل عدة مرات واستلم نتائج مماثلة. ثم أضفت 60،000 سجل آخر لما مجموعه 90،000، وكانت هذه الاختلافات في الأداء:

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

امل ان يساعد. أعلم أنه لا يفسر حقا السبب، ولكن هذا قد يساعد في كيفية. أيضا لا يصعب التخلص من التعليمات البرمجية لاستعلام حقل الصودا ليكون أكثر عام.

لم أفعل الكثير مع DB4O LinQ. ولكن يمكنك استخدام DiagnostictiConsole (أو Totrace) وإضافته إلى Iconfiguration.Diagnostic (). AdVerListener. هذا سيظهر لك إذا تم تحسين الاستعلام.

أنت لا تعطي الكثير من التفاصيل، ولكن هل هو ملك المعرف في مفهرف SimpleObject؟

بمجرد تشغيل التشخيص، قد تحاول الاستعلام مثل ...

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

معرفة ما إذا كان ذلك يمنحك خطة استفسارات مختلفة.

يمكنك "إنشاء استعلام LinQ الديناميكي. على سبيل المثال، يمكن أن تبدو API مثل هذا:

المعلمة الأولى: تعبير يحكي المنشار الذي تبحث فيه المعلمات الأخرى: المعرف أو ما تبحث عنه.

 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