Laden...

EF6 TimeOut bei Skip / Take und gewissen werten.

Erstellt von Palin vor 8 Jahren Letzter Beitrag vor 8 Jahren 4.075 Views
P
Palin Themenstarter:in
1.090 Beiträge seit 2011
vor 8 Jahren
EF6 TimeOut bei Skip / Take und gewissen werten.

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:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

A
8 Beiträge seit 2008
vor 8 Jahren

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.

P
Palin Themenstarter:in
1.090 Beiträge seit 2011
vor 8 Jahren

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:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

A
8 Beiträge seit 2008
vor 8 Jahren

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.

P
Palin Themenstarter:in
1.090 Beiträge seit 2011
vor 8 Jahren

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:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

A
8 Beiträge seit 2008
vor 8 Jahren

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.

P
Palin Themenstarter:in
1.090 Beiträge seit 2011
vor 8 Jahren

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, Action1 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&amp; 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.&lt;Reader&gt;b__c(DbCommand t, DbCommandInterceptionContext1 c)
bei System.Data.Entity.Infrastructure.Interception.InternalDispatcher1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func3 operation, TInterceptionContext interceptionContext, Action3 executing, Action3 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.&lt;&gt;c__DisplayClass3.&lt;GetResults&gt;b__2() bei System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
bei System.Data.Entity.Core.Objects.ObjectQuery1.&lt;&gt;c__DisplayClass3.&lt;GetResults&gt;b__1() bei System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func1 operation)
bei System.Data.Entity.Core.Objects.ObjectQuery1.GetResults(Nullable1 forMergeOption)
bei System.Data.Entity.Core.Objects.ObjectQuery1.&lt;System.Collections.Generic.IEnumerable&lt;T&gt;.GetEnumerator&gt;b__0() bei System.Data.Entity.Internal.LazyEnumerator1.MoveNext()
bei System.Collections.Generic.List1..ctor(IEnumerable1 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:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

M
184 Beiträge seit 2012
vor 8 Jahren

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...

P
Palin Themenstarter:in
1.090 Beiträge seit 2011
vor 8 Jahren

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:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

16.806 Beiträge seit 2008
vor 8 Jahren

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.

P
Palin Themenstarter:in
1.090 Beiträge seit 2011
vor 8 Jahren

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:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

16.806 Beiträge seit 2008
vor 8 Jahren

Kannst Du evtl. ein Beispielprojekt anhängen, bei dem ich das ausprobieren kann?
Evtl. mit LocalDB, sodass ich mir kein MSSQL installieren muss?

P
Palin Themenstarter:in
1.090 Beiträge seit 2011
vor 8 Jahren

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:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

P
Palin Themenstarter:in
1.090 Beiträge seit 2011
vor 8 Jahren

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:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

M
184 Beiträge seit 2012
vor 8 Jahren

Wenn du absolut nicht weiter kommst, dann könntest du dir den EntityFramework-Sourcecode laden und damit debuggen...

1.378 Beiträge seit 2006
vor 8 Jahren

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

P
Palin Themenstarter:in
1.090 Beiträge seit 2011
vor 8 Jahren

@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:

Clean Code Developer
Entwurfsmuster
Anti-Pattern