Skip to content

Instantly share code, notes, and snippets.

@riezebosch riezebosch/Program.cs
Last active Jul 27, 2017

Embed
What would you like to do?
Faster Find
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Core.Objects.DataClasses;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using Library;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
FunctionalTest();
PerformanceTest();
}
private static void FunctionalTest()
{
Console.WriteLine("Functional test");
ObjectCanBeRetreivedAfterAddingItToTheDbContext();
ObjectCannotBeRetreivedAfterDeletingItFromTheDbContext();
NestedObjectCanBeRetrieved();
NestedObjectCanBeRetrievedLateBound();
}
private static void ObjectCanBeRetreivedAfterAddingItToTheDbContext()
{
var customerIds = new IdGenerator();
using (var db = new MyDatabase())
{
var finder = new FasterFind(db);
db.Customers.Add(new Customer()
{
Id = customerIds.Next(),
Name = "Some name",
Orders = new List<Order>()
});
Debug.Assert(finder.Find<Customer>(customerIds.All().First()) != null);
Debug.Assert(finder.Find<Order>(customerIds.All().First()) == null);
}
}
private static void ObjectCannotBeRetreivedAfterDeletingItFromTheDbContext()
{
var customerIds = new IdGenerator();
using (var db = new MyDatabase())
{
var finder = new FasterFind(db);
var customer = db.Customers.Add(new Customer()
{
Id = customerIds.Next(),
Name = "Some name",
Orders = new List<Order>()
});
db.SaveChanges();
db.Customers.Remove(customer);
Debug.Assert(finder.Find<Customer>(customerIds.All().First()) == null);
db.SaveChanges();
Debug.Assert(finder.Find<Customer>(customerIds.All().First()) == null);
}
}
private static void NestedObjectCanBeRetrieved()
{
var customerIds = new IdGenerator();
var orderIds = new IdGenerator();
using (var db = new MyDatabase())
{
var finder = new FasterFind(db);
var customer = db.Customers.Add(new Customer()
{
Id = customerIds.Next(),
Name = "Some name",
Orders = new List<Order>()
{
new Order()
{
Id = orderIds.Next(),
}
}
});
Debug.Assert(finder.Find<Order>(orderIds.All().First()) != null);
db.SaveChanges();
Debug.Assert(finder.Find<Order>(orderIds.All().First()) != null);
}
}
private static void NestedObjectCanBeRetrievedLateBound()
{
// WARNING THIS IS THE ONLY USE-CASE THAT THIS
// IMPLEMENTATION DOES NOT SUPPORT - UNLESS SAVED WITH SAVECHANGES
var customerIds = new IdGenerator();
var orderIds = new IdGenerator();
using (var db = new MyDatabase())
{
var finder = new FasterFind(db);
var customer = db.Customers.Add(new Customer()
{
Id = customerIds.Next(),
Name = "Some name",
Orders = new List<Order>()
});
customer.Orders.Add(new Order()
{
Customer = customer,
Id = orderIds.Next(),
});
// This is the case where EF can find the object
// and our implementation cannot find it
// but EF is slow because of this 'only' case.
Debug.Assert(finder.Find<Order>(orderIds.All().First()) == null);
Debug.Assert(db.Orders.Find(orderIds.All().First()) != null);
db.SaveChanges();
Debug.Assert(finder.Find<Order>(orderIds.All().First()) != null);
}
}
private static void PerformanceTest()
{
Console.WriteLine("Performance test");
var customerIds = new IdGenerator();
var orderIds = new IdGenerator();
InitializeDatabase(customerIds, orderIds);
FasterFind ff = null;
Func<MyDatabase, Guid, Customer> ff_customer = (db, id) => (ff ?? (ff = new FasterFind(db))).Find<Customer>(id);
Func<MyDatabase, Guid, Customer> find_customer = (db, id) => db.Customers.Find(id);
Func<MyDatabase, Guid, Customer> fod_customer = (db, id) => db.Customers.FirstOrDefault(c => c.Id == id);
Func<MyDatabase, Guid, Customer> fod_customer_ant = (db, id) => db.Customers.AsNoTracking().FirstOrDefault(c => c.Id == id);
Func<MyDatabase, Guid, Order> ff_order = (db, id) => (ff ?? (ff = new FasterFind(db))).Find<Order>(id);
Func<MyDatabase, Guid, Order> find_order = (db, id) => db.Orders.Find(id);
Func<MyDatabase, Guid, Order> fod_order = (db, id) => db.Orders.FirstOrDefault(c => c.Id == id);
Func<MyDatabase, Guid, Order> fod_order_ant = (db, id) => db.Orders.AsNoTracking().FirstOrDefault(c => c.Id == id);
ExecutePerformanceTest(customerIds, orderIds, " 0% loaded - ff ", ff_customer, ff_order);
ff = null;
ExecutePerformanceTest(customerIds, orderIds, " 0% loaded - find ", find_customer, find_order);
ExecutePerformanceTest(customerIds, orderIds, " 0% loaded - fod ", fod_customer, fod_order);
ExecutePerformanceTest(customerIds, orderIds, " 0% loaded - fodnt", fod_customer_ant, fod_order_ant);
ExecutePerformanceTest(customerIds, orderIds, " 50% loaded - ff ", ff_customer, ff_order, db => InitializeHalf(db, customerIds, orderIds));
ff = null;
ExecutePerformanceTest(customerIds, orderIds, " 50% loaded - find ", find_customer, find_order, db => InitializeHalf(db, customerIds, orderIds));
ExecutePerformanceTest(customerIds, orderIds, " 50% loaded - fod ", fod_customer, fod_order, db => InitializeHalf(db, customerIds, orderIds));
ExecutePerformanceTest(customerIds, orderIds, " 50% loaded - fodnt", fod_customer_ant, fod_order_ant, db => InitializeHalf(db, customerIds, orderIds));
ExecutePerformanceTest(customerIds, orderIds, "100% loaded - ff ", ff_customer, ff_order, (db) => InitializeFull(db));
ff = null;
ExecutePerformanceTest(customerIds, orderIds, "100% loaded - find ", find_customer, find_order, (db) => InitializeFull(db));
ExecutePerformanceTest(customerIds, orderIds, "100% loaded - fod ", fod_customer, fod_order, (db) => InitializeFull(db));
ExecutePerformanceTest(customerIds, orderIds, "100% loaded - fodnt", fod_customer_ant, fod_order_ant, (db) => InitializeFull(db));
}
private static void InitializeDatabase(IdGenerator customerIds, IdGenerator orderIds)
{
using (var db = new MyDatabase())
{
for (int i = 0; i < 500; i++)
{
var customer = db.Customers.Add(new Customer()
{
Id = customerIds.Next(),
Name = "Some name",
Orders = new List<Order>()
});
for (int j = 0; j < 3; j++)
{
customer.Orders.Add(new Order()
{
Id = orderIds.Next(),
Customer = customer
});
}
}
db.SaveChanges();
}
}
private static void InitializeFull(MyDatabase db)
{
db.Customers.Include(z => z.Orders).ToArray();
}
private static void InitializeHalf(MyDatabase db, IdGenerator customerIds, IdGenerator orderIds)
{
db.Customers.Take(customerIds.All().Count() / 2).ToArray();
db.Orders.Take(orderIds.All().Count() / 2).ToArray();
}
static void ExecuteOnNewDbContext(Action<MyDatabase> action)
{
using (var database = new MyDatabase())
{
action(database);
}
}
static void ExecutePerformanceTest(IdGenerator customers,
IdGenerator orders,
string title,
Func<MyDatabase, Guid, Customer> customer,
Func<MyDatabase, Guid, Order> order,
Action<MyDatabase> setup = null
)
{
ExecuteOnNewDbContext(db =>
{
setup?.Invoke(db);
using (new PerformanceScope($"Customers - {title}"))
{
foreach (var id in customers.All())
{
customer(db, id);
}
}
using (new PerformanceScope($"Orders - {title}"))
{
foreach (var id in orders.All())
{
order(db, id);
}
}
});
}
}
}

origineel

query context type tijd
Elapsed for Customers DbContext.Find 0% loaded 525 ms
Elapsed for Orders DbContext.Find 0% loaded 4191 ms
Elapsed for Customers Finder.Find 0% loaded 296 ms
Elapsed for Orders Finder.Find 0% loaded 903 ms
Elapsed for Customers DbContext.Find 50% loaded 1372 ms
Elapsed for Orders DbContext.Find 50% loaded 6736 ms
Elapsed for Customers Finder.Find 50% loaded 305 ms
Elapsed for Orders Finder.Find 50% loaded 1045 ms
Elapsed for Customers DbContext.Find 100% loaded 26784 ms
Elapsed for Orders DbContext.Find 100% loaded 79507 ms
Elapsed for Customers Finder.Find 100% loaded 350 ms
Elapsed for Orders Finder.Find 100% loaded 848 ms

op volgorde

Let op! Inmiddels een paar test-runs verder waardoor er steeds meer data in de DB zit.

query context type tijd
Elapsed for Customers 0% loaded ff 312 ms
Elapsed for Orders 0% loaded ff 909 ms
Elapsed for Customers 0% loaded find 507 ms
Elapsed for Orders 0% loaded find 4086 ms
Elapsed for Customers 0% loaded fod 286 ms
Elapsed for Orders 0% loaded fod 883 ms
Elapsed for Customers 0% loaded fodnt 295 ms
Elapsed for Orders 0% loaded fodnt 844 ms
Elapsed for Customers 50% loaded ff 295 ms
Elapsed for Orders 50% loaded ff 914 ms
Elapsed for Customers 50% loaded find 1252 ms
Elapsed for Orders 50% loaded find 6390 ms
Elapsed for Customers 50% loaded fod 324 ms
Elapsed for Orders 50% loaded fod 1197 ms
Elapsed for Customers 50% loaded fodnt 348 ms
Elapsed for Orders 50% loaded fodnt 970 ms
Elapsed for Customers 100% loaded ff 310 ms
Elapsed for Orders 100% loaded ff 831 ms
Elapsed for Customers 100% loaded find 45460 ms
Elapsed for Orders 100% loaded find 140865 ms
Elapsed for Customers 100% loaded fod 436 ms
Elapsed for Orders 100% loaded fod 1038 ms
Elapsed for Customers 100% loaded fodnt 451 ms
Elapsed for Orders 100% loaded fodnt 1071 ms

gegroepeerd

query context type tijd
Elapsed for Customers 0% loaded ff 312 ms
Elapsed for Customers 0% loaded fod 286 ms
Elapsed for Orders 0% loaded ff 909 ms
Elapsed for Orders 0% loaded fod 883 ms
Elapsed for Customers 50% loaded ff 295 ms
Elapsed for Customers 50% loaded fod 324 ms
Elapsed for Orders 50% loaded ff 914 ms
Elapsed for Orders 50% loaded fod 1197 ms
Elapsed for Customers 100% loaded ff 310 ms
Elapsed for Customers 100% loaded fod 436 ms
Elapsed for Orders 100% loaded ff 831 ms
Elapsed for Orders 100% loaded fod 1038 ms
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.