Wie der Titel vermuten lässt, habe ich ein Problem mit der ersten Abfrage einer SQL Server-Datenbank unter Verwendung von Entity Framework. Ich habe versucht, nach einer Antwort zu suchen, aber niemand scheint tatsächlich eine Lösung dafür zu haben.
Die Tests wurden in Visual Studio 2012 mit Entity Framework 6 durchgeführt. Ich habe auch die T4-Ansichtenvorlage verwendet, um die Ansichten vorzukompilieren. Die Datenbank wurde auf einem SQL Server 2008 erstellt. Wir haben ungefähr 400 POCOs (400 Zuordnungsdateien), nur 100 Zeilen Daten in der Datenbanktabelle.
Nach dem Capture ist mein Testcode und Ergebnis.
static void Main(string[] args){
Stopwatch st=new Stopwatch();
st.Start();
new TestDbContext().Set<Table1>.FirstOrDefault();
st.stop();
Console.WriteLine("First Time "+st.ElapsedMilliseconds+ " milliseconds");
st.Reset();
st.Start();
new TestDbContext().Set<Table1>.FirstOrDefault();
st.stop();
Console.WriteLine("Second Time "+st.ElapsedMilliseconds+ " milliseconds");
}
Testergebnisse
First Time 15480 milliseconds
Second Time 10 milliseconds
Bei der ersten Abfrage kompiliert EF das Modell. Für ein so großes Modell kann dies einige Zeit in Anspruch nehmen.
Hier sind 3 Vorschläge: http://www.fusonic.net/de/blog/2014/07/09/drei-steps-for-fast-entityframework-6.1-first-query-performance/
Eine Zusammenfassung:
Ich würde auch sicherstellen, dass ich die Anwendung im Release-Modus kompiliere, wenn ich die Benchmarks durchführe.
Eine andere Lösung ist das Aufteilen von DBContext. 400 Entitäten sind eine Menge und es sollte schöner sein, mit kleineren Brocken zu arbeiten. Ich habe es nicht ausprobiert, aber ich gehe davon aus, dass es möglich wäre, die Modelle einzeln zu bauen, was bedeutet, dass keine einzelne Last 15 Sekunden benötigt. Sehen Sie diesen Beitrag von Julie Lerman https://msdn.Microsoft.com/en-us/magazine/jj883952.aspx
Mit EF Core können Sie das Modell frühzeitig cheaten und laden, nachdem Sie services.AddDbContext
aufgerufen haben (Sie können wahrscheinlich auch mit EF6 etwas ähnliches tun, aber ich habe es nicht getestet).
services.AddDbContext<MyDbContext>(options => ...);
var options = services.BuildServiceProvider()
.GetRequiredService<DbContextOptions<MyDbContext>>();
Task.Run(() =>
{
using(var dbContext = new MyDbContext(options))
{
var model = dbContext.Model; //force the model creation
}
});
Dadurch wird das Modell des dbcontext in einem anderen Thread erstellt, während der Rest der Initialisierung der Anwendung (und möglicherweise anderer Aufwärmvorgänge) und des Beginns einer Anforderung ausgeführt wird. Auf diese Weise wird es früher fertig sein. Wenn Sie es benötigen, wartet EFCore auf die Erstellung des Modells, wenn es noch nicht fertig ist. Die Variable Model
wird von allen DbContext-Instanzen gemeinsam genutzt. Es ist also in Ordnung, diesen Dummy-Dbcontext abzufeuern und zu vergessen.
Sie können so etwas versuchen: (es hat für mich funktioniert)
protected void Application_Start()
{
Start(() =>
{
using (EF.DMEntities context = new EF.DMEntities())
{
context.DMUsers.FirstOrDefault();
}
});
}
private void Start(Action a)
{
a.BeginInvoke(null, null);
}
Wenn Sie viele Tabellen haben, die nicht in c # verwendet werden, schließen Sie diese aus.
Fügen Sie eine Teilklasse hinzu, fügen Sie den folgenden Code hinzu und referenzieren Sie diese Funktion in OnModelCreating
void ExcludedTables(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<Table1>();
modelBuilder.Ignore<Table>();
// And so on
}
diese Arbeit für mich:
using (MyEntities db = new MyEntities())
{
db.Configuration.AutoDetectChangesEnabled = false; // <----- trick
db.Configuration.LazyLoadingEnabled = false; // <----- trick
DateTime Created = DateTime.Now;
var obj = from tbl in db.MyTable
where DateTime.Compare(tbl.Created, Created) == 0
select tbl;
dataGrid1.ItemsSource = obj.ToList();
dataGrid.Items.Refresh();
}