it-swarm.com.de

Ist dies ein Symptom für einen überlasteten Server?

Ich habe versucht, Verlangsamungen in einer Anwendung zu diagnostizieren. Dafür habe ich den SQL Server erweiterte Ereignisse protokolliert.

  • Für diese Frage betrachte ich eine bestimmte gespeicherte Prozedur.
  • Es gibt jedoch einen Kernsatz von einem Dutzend gespeicherter Prozeduren, die gleichermaßen als Untersuchung von Äpfeln zu Äpfeln verwendet werden können
  • und wenn ich eine der gespeicherten Prozeduren manuell ausführe, läuft sie immer schnell
  • und wenn ein Benutzer es erneut versucht: es wird schnell ausgeführt.

Die Ausführungszeiten der gespeicherten Prozedur variieren stark. Viele der Ausführungen dieser gespeicherten Prozedur werden in <1s zurückgegeben:

(enter image description here

Und für diesen "schnell" Eimer ist es viel weniger als 1s. Es ist tatsächlich ungefähr 90 ms:

(enter image description here

Aber es gibt einen langen Schwanz von Benutzern, die 2s, 3s, 4s Sekunden warten müssen. Einige müssen 12s, 13s, 14s warten. Dann gibt es die wirklich armen Seelen, die 22s, 23s, 24s warten müssen.

Und nach 30 Sekunden gibt die Client-Anwendung auf, bricht die Abfrage ab und der Benutzer musste warten Sekunden.

Korrelation, um die Ursache zu finden

Also habe ich versucht zu korrelieren:

  • dauer vs logische Lesevorgänge
  • dauer vs physische Lesevorgänge
  • dauer vs CPU-Zeit

Und keiner scheint eine Korrelation zu geben; keine scheint die Ursache zu sein

  • Dauer vs logische Lesevorgänge: ob ein wenig oder viele logische Lesevorgänge, die Dauer schwankt immer noch stark:

    (enter image description here

  • Dauer im Vergleich zu physischen Lesevorgängen: Auch wenn die Abfrage nicht aus dem Cache bereitgestellt wurde und viele physische Lesevorgänge erforderlich waren, hat dies keinen Einfluss auf die Dauer :

    (enter image description here

  • Dauer vs CPU-Zeit: Unabhängig davon, ob die Abfrage 0 Sekunden CPU-Zeit oder volle 2,5 Sekunden CPU-Zeit in Anspruch nahm, haben die Dauern dieselbe Variabilität:

    (enter image description here

Bonus: Ich habe festgestellt, dass Dauer v Physische Lesevorgänge und Dauer v CPU-Zeit ​​sehr ähnlich aussehen. Dies wird bewiesen, wenn ich versuche, die CPU-Zeit mit physischen Lesevorgängen zu korrelieren:

(enter image description here

Es stellt sich heraus, dass ein Großteil der CPU-Auslastung von E/A herrührt. Wer wusste!

Wenn es also nichts mit dem Vorgang von Ausführen der Abfrage zu tun hat, die die Unterschiede in der Ausführungszeit erklären kann, bedeutet dies, dass es sich nicht um eine CPU oder Festplatte handelt?

Wenn die CPU oder Festplatte der Engpass wäre; Wäre es nicht der Engpass?

Wenn wir annehmen, dass es die CPU war, die den Engpass darstellte; dass die CPU für diesen Server unterversorgt ist:

  • würden dann Ausführungen mit mehr CPU-Zeit nicht länger dauern?
  • da müssen sie mit anderen die überlastete CPU nutzen?

Ähnliches gilt für die Festplatten. Wenn wir annehmen, dass die Festplatte ein Engpass war; dass die Festplatten nicht genügend zufälligen Durchsatz für diesen Server haben:

  • würden dann nicht Ausführungen mit mehr physischen Lesevorgängen länger dauern?
  • da sie mit anderen über die überlastete Festplatten-E/A fertig werden müssen?

Die gespeicherte Prozedur selbst führt keine Schreibvorgänge aus und erfordert diese auch nicht.

  • Normalerweise werden 0 Zeilen (90%) zurückgegeben.
  • Gelegentlich wird 1 Zeile (7%) zurückgegeben.
  • In seltenen Fällen werden 2 Zeilen zurückgegeben (1,4%).
  • Und im schlimmsten Fall wurden mehr als 2 Zeilen zurückgegeben (einmal 12 Zeilen)

Es ist also nicht so, als würde ein wahnsinniges Datenvolumen zurückgegeben.

Server-CPU-Auslastung

Die Prozessorauslastung des Servers beträgt durchschnittlich 1,8%, mit einem gelegentlichen Anstieg von bis zu 18% - es scheint also nicht, dass die CPU-Auslastung ein Problem darstellt:

(enter image description here

Die Server-CPU scheint also nicht überlastet zu sein.

Aber der Server ist ​​virtuell ...

Etwas außerhalb des Universums?

Das einzige, was ich mir noch vorstellen kann, ist etwas, das außerhalb des Universums des Servers existiert.

  • wenn es nicht logisch liest
  • und es ist nicht physisch liest
  • und es ist keine CPU-Nutzung
  • und es ist nicht CPU-Last

Und es ist nicht so, als wären es die Parameter für die gespeicherte Prozedur (da die gleiche Abfrage manuell ausgegeben wird und es nicht 27 Sekunden dauert - es dauert ~ 0 Sekunden).

Was sonst könnte dafür verantwortlich sein, dass der Server manchmal 30 Sekunden anstatt 0 Sekunden benötigt, um dieselbe kompilierte gespeicherte Prozedur auszuführen.

  • checkpoints?

Es ist ein virtueller Server

  • der Host überlastet?
  • ein anderes VM auf demselben Host?

Durchlaufen der erweiterten Ereignisse des Servers; Es passiert nichts anderes, wenn eine Abfrage plötzlich 20 Sekunden dauert. Es läuft gut und entscheidet sich dann, nicht gut zu laufen:

  • 2 Sekunden
  • 1 Sekunde
  • Sekunden
  • 3 Sekunden
  • 2 Sekunden

Und es gibt keine anderen besonders anstrengenden Gegenstände, die ich finden kann. Es ist nicht während jeder 2-stündigen Transaktionsprotokollsicherung.

Was sonst könnte es sein?

Kann ich noch etwas sagen: "der Server"?

Bearbeiten: Korrelieren nach Tageszeit

Mir wurde klar, dass ich die Dauer mit allem korreliert habe:

  • logische Lesevorgänge
  • physische liest
  • cPU auslastung

Aber das einzige, mit dem ich es nicht korreliert habe, war die Tageszeit. Möglicherweise ist die Sicherung des Transaktionsprotokolls alle 2 Stunden ist ​​ein Problem.

Oder treten die Verlangsamungen do in Spannfuttern an Kontrollpunkten auf?

Nee:

(enter image description here

Intel Xeon Gold Quad-Core 6142.

Bearbeiten - Personen stellen den Ausführungsplan für Abfragen in Frage

Die Leute gehen davon aus, dass die Pläne zur Ausführung von Abfragen zwischen "schnell" und "langsam" unterscheiden müssen. Sie sind nicht.

Und das können wir sofort an der Inspektion erkennen.

Wir wissen, dass die längere Fragendauer nicht auf einen "schlechten" Ausführungsplan zurückzuführen ist:

  • eine, die logischer gelesen wurde
  • eine, die mehr CPU aus mehr Joins und Schlüsselsuchen verbraucht

Denn wenn eine Zunahme der Lesevorgänge oder eine Zunahme der CPU eine Ursache für eine längere Abfragedauer gewesen wäre, hätten wir das oben bereits gesehen. Es gibt keine Korrelation.

Versuchen wir jedoch, die Dauer mit der Produktmetrik für den CPU-Lesebereich zu korrelieren:

(enter image description here

Es wird noch weniger eine Korrelation - was ein Paradoxon ist.


Bearbeiten: Die Streudiagramme wurden aktualisiert, um einen Fehler in Excel-Streudiagrammen mit einer großen Anzahl von Werten zu umgehen.

Nächste Schritte

Meine nächsten Schritte werden darin bestehen, jemanden nach 5 Sekunden dazu zu bringen, Ereignisse für blockierte Abfragen auf dem Server zu generieren:

EXEC sp_configure 'blocked process threshold', '5';
RECONFIGURE

Es wird nicht erklärt, ob Abfragen für 4 Sekunden blockiert sind. Aber vielleicht blockiert alles, was eine Abfrage für 5 Sekunden blockiert, auch einige für 4 Sekunden.

Die langsamen Pläne

Hier ist der Slowplan der beiden gespeicherten Prozeduren, die ausgeführt werden:

  • `EXECUTE FindFrob @CustomerID = 7383, @StartDate = '20190725 04: 00: 00.000', @EndDate = '20190726 04: 00: 00.000'
  • `EXECUTE FindFrob @CustomerID = 7383, @StartDate = '20190725 04: 00: 00.000', @EndDate = '20190726 04: 00: 00.000'

Dieselbe gespeicherte Prozedur mit denselben Parametern wird hintereinander ausgeführt:

| Duration (us) | CPU time (us) | Logical reads | Physical reads | 
|---------------|---------------|---------------|----------------|
|    13,984,446 |        47,000 |         5,110 |            771 |
|     4,603,566 |        47,000 |         5,126 |            740 |

Rufen Sie 1 an:

|--Nested Loops(Left Semi Join, OUTER REFERENCES:([Contoso2].[dbo].[Frobs].[FrobGUID]) OPTIMIZED)
    |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]))
    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[RowNumber]) OPTIMIZED)
    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
    |    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
    |    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[TransactionPatronInfo].[IX_TransactionPatronInfo_CustomerID_TransactionGUID] AS [tpi]), SEEK:([tpi].[CustomerID]=[@CustomerID]) ORDERED FORWARD)
    |    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[Transactions].[IX_Transactions_TransactionGUIDTransactionDate]), SEEK:([Contoso2].[dbo].[Transactions].[TransactionGUID]=[Contoso2].[dbo
    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions2_MoneyAppearsOncePerTransaction]), SEEK:([Contoso2].[dbo].[FrobTransactions].[TransactionGUID]=[Contos
    |    |    |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions_RowNumber]), SEEK:([Contoso2].[dbo].[FrobTransactions].[RowNumber]=[Contoso2].[dbo].[Fin
    |    |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[Frobs].[PK_Frobs_FrobGUID]), SEEK:([Contoso2].[dbo].[Frobs].[FrobGUID]=[Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]),  WHERE:([Contos
    |--Filter(WHERE:([Expr1009]>(1)))
     |--Compute Scalar(DEFINE:([Expr1009]=CONVERT_IMPLICIT(int,[Expr1012],0)))
          |--Stream Aggregate(DEFINE:([Expr1012]=Count(*)))
           |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactins_OnFrobGUID]), SEEK:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]=[Contoso2].[dbo].[Frobs].[LC

Rufen Sie 2 an

|--Nested Loops(Left Semi Join, OUTER REFERENCES:([Contoso2].[dbo].[Frobs].[FrobGUID]) OPTIMIZED)
    |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]))
    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[RowNumber]) OPTIMIZED)
    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
    |    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
    |    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[TransactionPatronInfo].[IX_TransactionPatronInfo_CustomerID_TransactionGUID] AS [tpi]), SEEK:([tpi].[CustomerID]=[@CustomerID]) ORDERED FORWARD)
    |    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[Transactions].[IX_Transactions_TransactionGUIDTransactionDate]), SEEK:([Contoso2].[dbo].[Transactions].[TransactionGUID]=[Contoso2].[dbo
    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions2_MoneyAppearsOncePerTransaction]), SEEK:([Contoso2].[dbo].[FrobTransactions].[TransactionGUID]=[Contos
    |    |    |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions_RowNumber]), SEEK:([Contoso2].[dbo].[FrobTransactions].[RowNumber]=[Contoso2].[dbo].[Fin
    |    |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[Frobs].[PK_Frobs_FrobGUID]), SEEK:([Contoso2].[dbo].[Frobs].[FrobGUID]=[Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]),  WHERE:([Contos
    |--Filter(WHERE:([Expr1009]>(1)))
     |--Compute Scalar(DEFINE:([Expr1009]=CONVERT_IMPLICIT(int,[Expr1012],0)))
          |--Stream Aggregate(DEFINE:([Expr1012]=Count(*)))
           |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactins_OnFrobGUID]), SEEK:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]=[Contoso2].[dbo].[Frobs].[LC

Es ist sinnvoll, dass die Pläne identisch sind. Es führt dieselbe gespeicherte Prozedur mit denselben Parametern aus.

12
Ian Boyd

Werfen Sie einen Blick auf die wait_stats und es wird angezeigt, welche Engpässe auf Ihrem SQL Server am größten sind.

Ich hatte kürzlich ein Problem, bei dem eine externe Anwendung zeitweise langsam war. Das Ausführen gespeicherter Prozeduren auf dem Server selbst war jedoch immer schnell.

Die Leistungsüberwachung zeigte, dass SQL-Caches oder die RAM-Nutzung und IO auf dem Server) überhaupt keine Bedenken haben.

Was dazu beigetragen hat, die Untersuchung einzugrenzen, war die Abfrage der Wartestatistiken, die von SQL in sys.dm_os_wait_stats

Das ausgezeichnete Skript auf der SQLSkills-Website zeigt Ihnen diejenigen, die Sie am meisten erleben. Sie können dann Ihre Suche eingrenzen, um die Ursachen zu identifizieren.

Sobald Sie wissen, welche Wartezeiten die großen Probleme sind, können Sie mit diesem Skript eingrenzen, in welcher Sitzung/Datenbank die Wartezeiten auftreten:

SELECT OSW.session_id,
       OSW.wait_duration_ms,
       OSW.wait_type,
       DB_NAME(EXR.database_id) AS DatabaseName
FROM sys.dm_os_waiting_tasks OSW
INNER JOIN sys.dm_exec_sessions EXS ON OSW.session_id = EXS.session_id
INNER JOIN sys.dm_exec_requests EXR ON EXR.session_id = OSW.session_id
OPTION(Recompile);

Die obige Abfrage und weitere Details stammen von der MSSQLTips-Website .

Das sp_BlitzFirst Skript aus Brent Ozars Website zeigt Ihnen auch, was Verlangsamungen verursacht.

2
KevH