I am not an expert on this, and it might be good to post on the DB4O forums about it, but I think I have a solution. It involves not using LINQ and using SODA.
This is what I did. I created a quick project that populates the database with 30000 SimpleObject based on your post's definition. I then wrote a query to grab all the SimpleObjects from the database:
var simpleObjects = db.Query<SimpleObject>(typeof(SimpleObject));
When I wrapped a StopWatch around it, that run takes about 740 milliseconds. I then used your code to search for a 100 random numbers between 0 and 2999. The response was 772 ms, so based on that number I am assuming that it is pulling all the objects out of the database. I am not sure how to verify that, but later I think I proved it with performance.
I then went lower. From my understanding the LINQ provider from the DB4O team is just doing a translation into SODA. Therefore I figured that I would write a SODA query to test, and what I found was that using SODA against a property is bad for performance because it took 19902 ms to execute. Here is the 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;
}
So thinking about why this would be so bad, I decided to not use an auto-implemented property and define it my self because Properties are actually methods and not values:
public class SimpleObject
{
private int _id;
public int Id {
get
{ return _id; }
set
{ _id = value; }
}
}
I then rewrote the query to use the _id private field instead of the property. The performance was much better at about 91 ms. Here is that 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;
}
Just to make sure that it is was not a fluke, I ran the test run several times and recieved similar results. I then added another 60,000 records for a total of 90,000, and this was the performance differences:
GetAll: 2450 ms
GetWithOriginalCode: 2694 ms
GetWithSODAandProperty: 75373 ms
GetWithSODAandField: 77 ms
Hope that helps. I know that it does not really explain why, but this might help with the how. Also the code for the SODA field query would not be hard to wrap to be more generic.