verwendetes Datenbanksystem: SQL Server 2008 R2
Hallo Zusammen,
ich hab ein ganz komische Problem, bei Folgenden Code bekomme ich in der Letzten Zeile einen TimeOut.
result2 = result.Skip(51).Take(50).ToList().AsQueryable();
var result4 = result.Skip(49).Take(50).ToList().AsQueryable();
var result3 = result.Skip(50).Take(51).ToList().AsQueryable();
var result5 = result.Skip(50).Take(49).ToList().AsQueryable();
var result7 = result.Skip(40).Take(40).ToList().AsQueryable();
var result8 = result.Skip(60).Take(60).ToList().AsQueryable();
var result1 = result.Skip(50).Take(50).ToList().AsQueryable(); <- TimeOut
Die Vorangegangenen Abfragen funktionieren (99ms/31ms 2. Abfrage) und wurden hier wirklich direkt hinter einander Ausgeführt. Die Abfragen habe ich zum Teil vorher auch Einzel ausgeführt. Da kam es auch nur bei der letzten zu einem TimeOut.
Ich sehe aktuell nicht ansatzweise woran es liegen könnte. (Sehr wahrscheinlich ein dummer Fehler von mir aber ich sehe es nicht.
Sollte man mal gelesen haben:
Zunächst ist das sehr suboptimal umgesetzt, da bei jeder Zeile die komplette Query erneut ausgeführt wird. Wenn das so gewollt ist, bitte sehr. Ansonsten würde ich mir die ersten 120 Datensätze (wenn ich mich nicht verzählt habe) in eine Liste laden und dann die einzelnen Segmente separieren.
Zu deiner Frage: Um diese zu beantworten, benötigt man imho das Tabellenlayout oder einfacher: Den SQL-Befehl, den EF in der letzten Zeile absetzt.
Alles geht.
Das ist natürlich nicht die produktive Implementierung. Im Eindefekt wird ein IQueryabel (deshalb auch der Cast) zurück gegeben um in der UI Pageing umzusetzen. Wo es dann zu TimeOuts kommt.
Bei der Untersuchung konnte ich Feststellen, das mit Skip(50).Take(50) sich der TimeOut reproduzieren lässt. Der nächste schritt war dann, das von Linq erzeugte SQL direkt auf dem Server auszuführen (wenn es da schon lange dauert, wird es in Programm auch nicht funktionieren). Das Funktionierte aber problemlos. Nach dem ich ein paar Sachen Probiert hatte, bin ich hingegange und hab Skip auf 49 gesetzt, um die Query auf den SQL Server besser erkennen zu können. Die lief aber problem los durch. Die Nächte Vermutung war, dass es vielleicht am letzten Datensatz liegt, der Fehlt ja bei Skip(49). Also hab ich Skip auf 51 gesetzt, damit der Datensatz mit dabei ist, was aber auch problemlos funktionierte. Das das Problem auftritt wenn der 1 und letzte Datensatz Enthalten sind hab ich mit Skip(50).Take(51) geprüft, lief auch problemlos.
Aktuell fehlt mir ein Ansatz woran es liegen könnte. Meine Arbeitskollegen hab ich auch schon gefragt, die haben aber auch keinen Ansatz.
Das es ein Grundlegendes Problem bei Skip/Take gibt schließe ich eigentlich aus. Dafür ist Linq zu oft im Einsatz.
Am Wahrscheinlichsten, ist das ich etwas Dummes mache. Ich sehe es aber einfach nicht. Mit meinem Blickwinkel auf Problem, stehe ich mir da wohl selber gerade im Weg. Und da hoffe ich einfach auf das Forum. Ich bin für jede Idee dankbar.
Sollte man mal gelesen haben:
Linq2SQL übersetzt doch auch nur LINQ in SQL, d.h. wie sieht der konkrete Befehl denn aus? Deiner Antwort entnehme ich nicht, dass Du den konkreten Befehl im SSMS ausgeführt hast.
Ich tippe (blind) auf einen Fehler im SQL-Server. Also kein Bug, sondern irgend etwas mit der Query.
Alles geht.
Der nächste schritt war dann, das von Linq erzeugte SQL direkt auf dem Server auszuführen (wenn es da schon lange dauert, wird es in Programm auch nicht funktionieren)
Linq2SQL übersetzt doch auch nur LINQ in SQL, d.h. wie sieht der konkrete Befehl denn aus? Deiner Antwort entnehme ich nicht, dass Du den konkreten Befehl im SSMS ausgeführt hast.
Ja hab ich gemacht.
Danke trozdem für die Antwort. Ich bin für jeder hilfe dankbar.
Sollte man mal gelesen haben:
Hupsa, übersehen... Aber der Timeout kommt von... wem? Das müsste sich aus der Exception ergeben. Da meckert doch ADO.NET, oder? Mit dem Profiler müsste man zudem genau erkennen können, was der Server so alles macht.
Nächster Versuch: Erzeuge eine Testtabelle und verwende dein Konstrukt dafür.
Klappt das? Wenn ja: Wo sind die Unterschiede?
Was ist 'result'? Ist das bereits ein Linq-Konstrukt? Müsste es eigentlich.
EDIT: Hier stand Murks: Erst testen, dann posten...
Alles geht.
Bei der Exception sehe ich jetzt nicht ungewöhliches, ist für mich einfach ein TimeOut
Fehlermeldung:
System.Data.Entity.Core.EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Timeout abgelaufen. Das Zeitlimit wurde vor dem Beenden des Vorgangs überschritten oder der Server reagiert nicht. ---> System.ComponentModel.Win32Exception: Der Wartevorgang wurde abgebrochen
--- Ende der internen Ausnahmestapelüberwachung ---
bei System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) bei System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action
1 wrapCloseInAction)
bei System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
bei System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
bei System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
bei System.Data.SqlClient.SqlDataReader.get_MetaData()
bei System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
bei System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
bei System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource1 completion, Int32 timeout, Task& task, Boolean asyncWrite) bei System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) bei System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) bei System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) bei System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) bei System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<Reader>b__c(DbCommand t, DbCommandInterceptionContext
1 c)
bei System.Data.Entity.Infrastructure.Interception.InternalDispatcher1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func
3 operation, TInterceptionContext interceptionContext, Action3 executing, Action
3 executed)
bei System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)
bei System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(CommandBehavior behavior)
bei System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
bei System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
--- Ende der internen Ausnahmestapelüberwachung ---
bei System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
bei System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan.Execute[TResultType](ObjectContext context, ObjectParameterCollection parameterValues)
bei System.Data.Entity.Core.Objects.ObjectQuery1.<>c__DisplayClass3.<GetResults>b__2() bei System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func
1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
bei System.Data.Entity.Core.Objects.ObjectQuery1.<>c__DisplayClass3.<GetResults>b__1() bei System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func
1 operation)
bei System.Data.Entity.Core.Objects.ObjectQuery1.GetResults(Nullable
1 forMergeOption)
bei System.Data.Entity.Core.Objects.ObjectQuery1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0() bei System.Data.Entity.Internal.LazyEnumerator
1.MoveNext()
bei System.Collections.Generic.List1..ctor(IEnumerable
1 collection)
bei System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
Ja result ist ist ein Linq Konstrukt, mit joins über mehrere Tabellen mit einer where und order by Klauseln.
Grundlegend funktioniert die Abfrage auch auf die Tabellen. Ich darf hald bei Skip/Take nur den Wert 50 nicht verwenden.
Die Abfrage(1) funktioniert.
return result.Skip(49).Take(51).ToList().AsQueryable();
Sie ist schnell und liefert mir die erwateten Werte zurück.
Die Abfrage(2) funktioniert nicht.
return result.Skip(50).Take(50).ToList().AsQueryable();
Die läuft auf ein TimeOut, dabei ist da eigendlich nur 1 Datensatz weniger drin als in Abfrage(1). (Ich hab da jetzt wirklich nur die Zahlen geändert).
Ich verstehe es einfach nicht 🤔
Sollte man mal gelesen haben:
Kannst du einmal die beiden SQL-Abfragen posten, die das EF dir generiert?
Irgendwo muss ein Unterschied sein... Oder die Ergebnismenge für Abfrage 2 ist wesentlich größer als bei Abfrage 1 und irgendein Index greift hier nicht...
Klar hab es mal vom Context Geloggt.
context.Database.Log = s => _logger.Error(s);
Das Funktioniernde sieht so aus.
SELECT TOP (51)
[Project1].[tblPcb_ID] AS [tblPcb_ID],
[Project1].[Barcode] AS [Barcode],
[Project1].[ProgrammName] AS [ProgrammName],
[Project1].[Charge] AS [Charge],
[Project1].[DateTime] AS [DateTime],
[Project1].[tblTraceState_ID] AS [tblTraceState_ID],
[Project1].[IdentNr] AS [IdentNr],
[Project1].[KurzName] AS [KurzName],
[Project1].[LinienNr] AS [LinienNr],
[Project1].[MaschinenNr] AS [MaschinenNr],
[Project1].[tblPcb_Name] AS [tblPcb_Name]
FROM ( SELECT [Project1].[tblPcb_ID] AS [tblPcb_ID], [Project1].[tblPcb_Name] AS [tblPcb_Name], [Project1].[tblTraceState_ID] AS [tblTraceState_ID], [Project1].[DateTime] AS [DateTime], [Project1].[MaschinenNr] AS [MaschinenNr], [Project1].[LinienNr] AS [LinienNr], [Project1].[Barcode] AS [Barcode], [Project1].[Charge] AS [Charge], [Project1].[IdentNr] AS [IdentNr], [Project1].[KurzName] AS [KurzName], [Project1].[ProgrammName] AS [ProgrammName], row_number() OVER (ORDER BY [Project1].[tblTraceState_ID] DESC) AS [row_number]
FROM ( SELECT
[Extent1].[tblPcb_ID] AS [tblPcb_ID],
[Extent1].[tblPcb_Name] AS [tblPcb_Name],
[Extent2].[tblTraceState_ID] AS [tblTraceState_ID],
[Extent2].[DateTime] AS [DateTime],
[Extent2].[MaschinenNr] AS [MaschinenNr],
[Extent2].[LinienNr] AS [LinienNr],
[Extent3].[Barcode] AS [Barcode],
[Extent3].[Charge] AS [Charge],
[Extent4].[IdentNr] AS [IdentNr],
[Extent5].[KurzName] AS [KurzName],
[Extent6].[ProgrammName] AS [ProgrammName]
FROM [dbo].[BESTPcb] AS [Extent1]
INNER JOIN [dbo].[TraceState] AS [Extent2] ON [Extent1].[tblPcb_ID] = [Extent2].[tblPcb_ID]
INNER JOIN [dbo].[LAGERStore] AS [Extent3] ON [Extent2].[tblStore_ID] = [Extent3].[tblStore_ID]
INNER JOIN [dbo].[BLIBComponent] AS [Extent4] ON [Extent3].[tblComponent_ID] = [Extent4].[tblComponent_ID]
LEFT OUTER JOIN [dbo].[BESTPosition] AS [Extent5] ON [Extent2].[tblPosition_ID] = [Extent5].[tblPosition_ID]
INNER JOIN [dbo].[BESTReference] AS [Extent6] ON [Extent1].[tblReference_ID] = [Extent6].[tblReference_ID]
WHERE ([Extent1].[tblPcb_Name] = @p__linq__0) OR (([Extent1].[tblPcb_Name] IS NULL) AND (@p__linq__0 IS NULL))
) AS [Project1]
) AS [Project1]
WHERE [Project1].[row_number] > 49
ORDER BY [Project1].[tblTraceState_ID] DESC
p__linq__0: '1/1' (Type = String, Size = 4000)
Executing at 27.07.2015 14:00:23 +02:00
Completed in 79 ms with result: SqlDataReader
Das nicht funktionierende so:
SELECT TOP (50)
[Project1].[tblPcb_ID] AS [tblPcb_ID],
[Project1].[Barcode] AS [Barcode],
[Project1].[ProgrammName] AS [ProgrammName],
[Project1].[Charge] AS [Charge],
[Project1].[DateTime] AS [DateTime],
[Project1].[tblTraceState_ID] AS [tblTraceState_ID],
[Project1].[IdentNr] AS [IdentNr],
[Project1].[KurzName] AS [KurzName],
[Project1].[LinienNr] AS [LinienNr],
[Project1].[MaschinenNr] AS [MaschinenNr],
[Project1].[tblPcb_Name] AS [tblPcb_Name]
FROM ( SELECT [Project1].[tblPcb_ID] AS [tblPcb_ID], [Project1].[tblPcb_Name] AS [tblPcb_Name], [Project1].[tblTraceState_ID] AS [tblTraceState_ID], [Project1].[DateTime] AS [DateTime], [Project1].[MaschinenNr] AS [MaschinenNr], [Project1].[LinienNr] AS [LinienNr], [Project1].[Barcode] AS [Barcode], [Project1].[Charge] AS [Charge], [Project1].[IdentNr] AS [IdentNr], [Project1].[KurzName] AS [KurzName], [Project1].[ProgrammName] AS [ProgrammName], row_number() OVER (ORDER BY [Project1].[tblTraceState_ID] DESC) AS [row_number]
FROM ( SELECT
[Extent1].[tblPcb_ID] AS [tblPcb_ID],
[Extent1].[tblPcb_Name] AS [tblPcb_Name],
[Extent2].[tblTraceState_ID] AS [tblTraceState_ID],
[Extent2].[DateTime] AS [DateTime],
[Extent2].[MaschinenNr] AS [MaschinenNr],
[Extent2].[LinienNr] AS [LinienNr],
[Extent3].[Barcode] AS [Barcode],
[Extent3].[Charge] AS [Charge],
[Extent4].[IdentNr] AS [IdentNr],
[Extent5].[KurzName] AS [KurzName],
[Extent6].[ProgrammName] AS [ProgrammName]
FROM [dbo].[BESTPcb] AS [Extent1]
INNER JOIN [dbo].[TraceState] AS [Extent2] ON [Extent1].[tblPcb_ID] = [Extent2].[tblPcb_ID]
INNER JOIN [dbo].[LAGERStore] AS [Extent3] ON [Extent2].[tblStore_ID] = [Extent3].[tblStore_ID]
INNER JOIN [dbo].[BLIBComponent] AS [Extent4] ON [Extent3].[tblComponent_ID] = [Extent4].[tblComponent_ID]
LEFT OUTER JOIN [dbo].[BESTPosition] AS [Extent5] ON [Extent2].[tblPosition_ID] = [Extent5].[tblPosition_ID]
INNER JOIN [dbo].[BESTReference] AS [Extent6] ON [Extent1].[tblReference_ID] = [Extent6].[tblReference_ID]
WHERE ([Extent1].[tblPcb_Name] = @p__linq__0) OR (([Extent1].[tblPcb_Name] IS NULL) AND (@p__linq__0 IS NULL))
) AS [Project1]
) AS [Project1]
WHERE [Project1].[row_number] > 50
ORDER BY [Project1].[tblTraceState_ID] DESC
p__linq__0: '1/1' (Type = String, Size = 4000)
-- Executing at 27.07.2015 14:02:03 +02:00
-- Failed in 30193 ms with error: Timeout abgelaufen. Das Zeitlimit wurde vor dem Beenden des Vorgangs überschritten oder der Server reagiert nicht.
Closed connection at 27.07.2015 14:02:33 +02:00
Sollte man mal gelesen haben:
Kann das sein, dass das zusätzliche Element, das Du hier lädst, irgendwie fehlerhaft ist und dadurch das Timeout ausgelöst wird?
Der Query ist nämlich soweit identisch.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Die 1. funktionierende Abfrage enthält ja, alle Elemente der 2. Abfrage (und sogar ein mehr).
Abfrage 1 bringt mir die Zeile 49 (+51) bis 100.
Abfrage 2 bringt mir die Zeile 50 (+50) bis 100.
Anders herum könnte ich es verstehen, dann wäre ein Fehler (Defekter Datensatz) in Zeile 49.
Sollte man mal gelesen haben:
Kannst Du evtl. ein Beispielprojekt anhängen, bei dem ich das ausprobieren kann?
Evtl. mit LocalDB, sodass ich mir kein MSSQL installieren muss?
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Die DB ist grob 11GB groß (20Millionendatensätze), wobei ca. 90% der Daten in der TraceState Tabelle sind. Welche in der Abfrage mit drin ist ohne Skip/Take liefert die Abfrage grob 20.000 Datensätze zurück.
Ich denke nicht, das ich da Ansatzweise realistisch die Daten bereitstellen kann.
Da an anderen stellen im Programm auch Skip/Take verwendet wird und problemlos funktioniert, befürchte ich das sich der Fehler nicht Reproduzieren lässt, wenn ich probiere da eine Abgespeckte Variante erzeuge. (Ich kann dir aber Anbieten per TeamViewer auf meinen Rechner zu schauen)
Sollte man mal gelesen haben:
Hallo Zusammen,
ich war mal so frei die Frage auch im MSDN Forum zu stellen. Weil ich da aktuell echt auch dem Schlauch stehen. Falls ich dort eine Hilfreiche Antwort bekomme. Poste ich sie natürlich hier.
MFG
Björn
Sollte man mal gelesen haben:
Wenn du absolut nicht weiter kommst, dann könntest du dir den EntityFramework-Sourcecode laden und damit debuggen...
Hallo Palin,
wie hast du denn das SQL der Statements extrahiert? Per SQL-Profiler? Falls nicht würde ich das nochmal probieren: Die komplette Abfrage (nicht nur die einzelnen separiert) im Profiler loggen lassen und dann gemeinsam im SSMS ausführen lassen um zu sehen obs dort funktioniert.
Weiters kann es sein (und hatte ich schonmal), dass Sachen im SSMS funktionieren, die aber im PGM nicht funktionierten. Ich kann mich nur mehr grob daran erinnern, dass "SET ARITHABORT OFF/ON" da teilweise geholfen hat bzw. kann es auch Probleme mit dem Ausführungsplänen im SQL Server geben. Evt. mal die irgendwo resetten probieren.
Wie schauts aus, wenn du das Timeout anhebst? Wird die anfrage dann fertig oder nicht?
Lg, XXX
@xxxprod ich hate das TimeOut schon mal höher gestellt (180), damit war es nicht durchgelaufen. Ich hatte dann jetzt auf deine Anfrage das TimeOut mal auf 1000 gesetzt, damit ist die Abfrage dann durchgelaufen.
Meine aktuelle Vermutung ist, das der Server für die Funktionierende Abfrage, auf eine Vorher schon ausgeführte Abfrage zurück gegriffen hat. Wehrend er bei der anderen die Abfrage neu erstellt hat was zu einem TimeOut führte.
Nun ja erst mal funktionierst und ich hab einen Ansatz voran es liegen könnte.
Danke an alle für die Unterstützung.
MFG
Björn
Sollte man mal gelesen haben: