문제

데이터베이스에 30,000 개의 단순 개체를 저장했습니다.

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

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로 객체로 위임한다는 것을 의미합니다).

가장 좋은 방법은 N 쿼리를 실행하는 것입니다 (ID 필드가 색인화되므로 각 쿼리가 빠르게 실행되어야 함) "Mark Hall"에서 제안한 결과를 집계하는 것입니다.

당신은 이것에 대해 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로 데이터베이스를 채우는 빠른 프로젝트를 만들었습니다. 그런 다음 데이터베이스에서 모든 간단한 작업을 가져 오기 위해 쿼리를 작성했습니다.

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

내가 그 주위에 스톱워치를 감았을 때, 그 실행은 약 740 밀리 초가 걸립니다. 그런 다음 코드를 사용하여 0에서 2999 사이의 100 랜덤 숫자를 검색했습니다. 응답은 772ms 였으므로 해당 숫자를 기준으로 모든 객체를 데이터베이스에서 끌어 내고 있다고 가정합니다. 나는 그것을 어떻게 확인 해야할지 잘 모르겠지만 나중에 나는 그것을 성능으로 증명했다고 생각합니다.

그런 다음 더 낮게 갔다. DB4O 팀의 LINQ 제공 업체가 이해를 통해 소다로 번역을하고 있습니다. 따라서 나는 테스트하기 위해 소다 쿼리를 작성할 것이라고 생각했고, 제가 찾은 것은 재산에 소다를 사용하는 것이 19902ms가 실행하는 데 걸렸 기 때문에 성능에 좋지 않다는 것입니다. 코드는 다음과 같습니다.

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 개인 필드를 사용합니다. 성능은 약 91ms에 훨씬 더 좋았습니다. 다음은 코드입니다.

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

도움이되기를 바랍니다. 나는 그것이 왜 이유를 설명하지는 않지만, 이것은 방법에 도움이 될 수 있습니다. 또한 소다 필드 쿼리의 코드는 더 일반적으로 포장하기 어렵지 않습니다.

DB4O LINQ로 많이하지 않았습니다. 그러나 DiagnostOconsole (또는 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