Ich habe ein Legacy .Net 4-Projekt (nennen wir es "A"), das Linq-to-SQL verwendet, um eine Datenbank abzufragen, und ich habe ein weiteres .Net 4-Projekt (nennen wir es "B") mit ähnlichem, aber nicht gleichem Code, das dieselbe Datenbank wie "A" abfragt.
Beide Projekte:
- sind C#-Projekte {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- verwenden dieselben Assemblys (Version v4.0.30319, derselbe Ordner)
- System.dll
- System.Data.dll
- System.Data.Linq.dll
Der automatisch generierte DataContext ist spezifisch für jedes Projekt, wird aber auf dieselbe Weise instanziiert:
- gleiche Verbindungszeichenfolge unter Verwendung der SQL-Authentifizierung
- beide DataContext setzen ihren CommandTimeout von Standard auf 60 Sekunden
- alle anderen Konfigurationsoptionen für den DataContext sind die Standardeinstellungen
Die Art und Weise, wie die Linq-Abfrage konstruiert ist, ist für die Projekte nicht genau gleich, aber die resultierende Linq-Abfrage ist identisch. Das generierte (T-)SQL-SELECT-Statement ist ebenfalls dasselbe! (SQL-Handles auf dem DB-Server überwacht und überprüft)
Der Datenbankserver ist:
- Microsoft SQL Server Enterprise 2005 x64 (9.00.4035.00)
- Betriebssystem: Microsoft Server 2003 R2 SP2 x64
Wenn die überwachte CPU-Zeit (auf dem DB-Server) für die Abfrage von Projekt "A" stark anstieg und eine Befehlszeitüberschreitungsausnahme ausgelöst wurde. (System.Data.SqlClient.SqlException: Timeout abgelaufen)
Andererseits wurde die Abfrage von "B" innerhalb von Sekunden ausgeführt (ungefähr 3). Ich konnte das Verhalten reproduzieren, indem ich den Code von "A" mit denselben Parametern erneut aufgerufen habe (keine Änderungen am Code oder der Datenbank). "B" wurde sogar innerhalb von Sekunden ausgeführt, während "A" seine CPU-Zeit erhöhte.
Bereut, nachdem ein Kollege die Indizes neu erstellt hatte, konnte ich das Verhalten nicht mehr reproduzieren. Derselbe Kollege erwähnte, dass die Abfrage "letzten Monat" schnell lief (obwohl sich der Code seit "letztem Monat" nicht geändert hat...).
Ich habe den Code für beide Projekte debuggt - beide DataContext-Instanzen sahen gleich aus. Der SQL-Handle des DB-Serverprozesses enthält denselben SQL-Befehl. Aber "A" warf eine Zeitüberschreitungsausnahme und "B" wurde wiederholt innerhalb von Sekunden ausgeführt!
Warum verbraucht dieselbe Linq-to-SQL-Abfrage beim Projekt "A" auf dem Datenbankserver viel mehr CPU-Zeit als beim Projekt "B"?
Ganz genau: Wenn die Abfrage "langsam" läuft aus bestimmten Gründen - wiederholt - wie kann dann dieselbe Abfrage schneller ausgeführt werden, nur weil sie von einem anderen Linq-to-SQL-Code aufgerufen wird?
Gibt es möglicherweise Nebenwirkungen, von denen ich noch nichts weiß? Gibt es bestimmte Instanzwerte des DataContext, auf die ich zur Laufzeit speziell achten muss?
Übrigens: Der SQL-Befehl - über SSMS - verwendet bei jedem Durchlauf denselben Abfrageplan.
Zur Vollständigkeit habe ich ein Beispiel von verlinkt:
- den C#-Code-Fragmenten des Projekts "B" (der Teil SqlRequest.GetQuery sieht für beide Projekte gleich aus)
- die SQL-Datei enthält das entsprechende Datenbankschema
- den Datenbank-Ausführungsplan
Bitte beachten Sie, dass ich das vollständige Datenbankschema oder den Code oder die tatsächlichen Daten, gegen die ich Abfragen durchführen, nicht offenlegen kann. (Die SQL-Tabellen haben weitere Spalten neben den genannten und der C#-Code ist etwas komplexer, weil die Linq-Abfrage bedingt konstruiert ist.)
Update - mehr Einblick zur Laufzeit
Einige Eigenschaften beider DataContext
-Instanzen:
Log = null;
Transaction = null;
CommandTimeout = 60;
Connection: System.Data.SqlClient.SqlConnection;
Die SqlConnection wurde aus einer Verbindungszeichenfolge wie dieser erstellt (in beiden Fällen):
"Data Source=server;Initial Catalog=sourceDb;Persist Security Info=True;User ID=user;Password=password"
Es werden keine expliziten SqlCommands ausgeführt, um SET
-Optionen an die Datenbanksession zu übergeben. Auch enthalten die inline TVF SET
-Optionen nicht.