SQL Server-Leistung: PREEMPTIVE_OS_DELETESECURITYCONTEXT dominanter Wartetyp


8

Ich habe gestern einen Anruf von einem Kunden erhalten, der sich über eine hohe CPU-Auslastung auf seinem SQL Server beschwert hat. Wir verwenden SQL Server 2012 64-Bit-SE. Auf dem Server wird Windows Server 2008 R2 Standard ausgeführt, 2,20 GHz Intel Xeon (4 Kerne), 16 GB RAM.

Nachdem ich sichergestellt hatte, dass der Schuldige tatsächlich SQL Server war, habe ich mir die oberen Wartezeiten für die Instanz mit der DMV-Abfrage hier angesehen . Die beiden obersten Wartezeiten waren: (1) PREEMPTIVE_OS_DELETESECURITYCONTEXTund (2) SOS_SCHEDULER_YIELD.

EDIT : Hier ist das Ergebnis der "Top Waits Query" (obwohl heute Morgen jemand den Server gegen meinen Willen neu gestartet hat):

Geben Sie hier die Bildbeschreibung ein

Wir führen viele intensive Berechnungen / Umrechnungen durch, damit ich verstehen kann SOS_SCHEDULER_YIELD. Ich bin jedoch sehr gespannt auf den PREEMPTIVE_OS_DELETESECURITYCONTEXTWartetyp und warum er der höchste sein könnte.

Die beste Beschreibung / Diskussion, die ich zu diesem Wartetyp finden kann, finden Sie hier . Es erwähnt:

Die Wartetypen PREEMPTIVE_OS_ sind Aufrufe, die das Datenbankmodul verlassen haben, normalerweise an eine Win32-API, und Code außerhalb von SQL Server für verschiedene Aufgaben ausführen. In diesem Fall wird ein Sicherheitskontext gelöscht, der zuvor für den Remote-Ressourcenzugriff verwendet wurde. Die zugehörige API heißt tatsächlich DeleteSecurityContext ()

Meines Wissens haben wir keine externen Ressourcen wie Verbindungsserver oder Dateitabellen. Und wir machen keinen Identitätswechsel usw. Könnte ein Backup dazu geführt haben, dass dies zu einem Anstieg führt, oder möglicherweise ein fehlerhafter Domänencontroller?

Was zum Teufel könnte dazu führen, dass dies der dominierende Wartetyp ist? Wie kann ich diesen Wartetyp weiter verfolgen?

Bearbeiten 2: Ich habe den Inhalt des Windows-Sicherheitsprotokolls überprüft. Ich sehe einige Einträge, die von Interesse sein könnten, bin mir aber nicht sicher, ob diese normal sind:

Special privileges assigned to new logon.

Subject:
    Security ID:        NT SERVICE\MSSQLServerOLAPService
    Account Name:       MSSQLServerOLAPService
    Account Domain:     NT Service
    Logon ID:       0x3143c

Privileges:     SeImpersonatePrivilege

Special privileges assigned to new logon.

Subject:
    Security ID:        NT SERVICE\MSSQLSERVER
    Account Name:       MSSQLSERVER
    Account Domain:     NT Service
    Logon ID:       0x2f872

Privileges:     SeAssignPrimaryTokenPrivilege
            SeImpersonatePrivilege

Bearbeiten Sie 3 : @ Jon Seigel, wie Sie angefordert haben, hier sind die Ergebnisse Ihrer Anfrage. Ein bisschen anders als bei Paul:

Geben Sie hier die Bildbeschreibung ein

Edit 4: Ich gebe zu, ich bin zum ersten Mal ein Extended Events-Benutzer. Ich habe diesen Wartetyp zum Ereignis wait_info_external hinzugefügt und Hunderte von Einträgen gesehen. Es gibt keinen SQL-Text oder Plan-Handle, nur einen Aufrufstapel. Wie kann ich die Quelle weiter aufspüren?

Geben Sie hier die Bildbeschreibung ein


John, kannst du bitte sp_whoisactive für einen bestimmten Zeitraum (vielleicht eine Minute) ausführen und sehen, was auftaucht? Dies kann Ihnen / uns helfen, eine Lösung zu finden. sqlblog.com/files/default.aspx
Mark Wilkinson

Hallo John, in Ihrer Frage erwähnen Sie, dass Sie SQL Server als Schuldigen identifiziert haben. Könnten Sie bitte die Schritte beschreiben, die Sie unternommen haben, um zu diesem Schluss zu kommen?
Craig Efrein

Antworten:


3

Ich weiß, dass diese Frage, basierend auf dem Titel, hauptsächlich den Wartetyp PREEMPTIVE_OS_DELETESECURITYCONTEXT betrifft, aber ich glaube, dass dies eine Fehlleitung des wahren Problems ist, nämlich " ein Kunde, der sich über eine hohe CPU-Auslastung auf seinem SQL Server beschwert hat ".

Der Grund, warum ich glaube, dass die Konzentration auf diesen speziellen Wartetyp eine wilde Gänsejagd ist, liegt darin, dass sie für jede hergestellte Verbindung hochgeht. Ich führe die folgende Abfrage auf meinem Laptop aus (dh ich bin der einzige Benutzer):

SELECT * 
FROM sys.dm_os_wait_stats
WHERE wait_type = N'PREEMPTIVE_OS_DELETESECURITYCONTEXT'

Und dann mache ich eine der folgenden Aktionen und führe diese Abfrage erneut aus:

  • Öffnen Sie eine neue Abfrage-Registerkarte
  • Schließen Sie die neue Registerkarte "Abfrage"
  • Führen Sie an einer DOS-Eingabeaufforderung Folgendes aus: SQLCMD -E -Q "select 1"

Jetzt wissen wir, dass die CPU hoch ist, also sollten wir uns ansehen, was läuft, um zu sehen, welche Sitzungen eine hohe CPU haben:

SELECT req.session_id AS [SPID],
       req.blocking_session_id AS [BlockedBy],
       req.logical_reads AS [LogReads],
       DB_NAME(req.database_id) AS [DatabaseName],
       SUBSTRING(txt.[text],
                 (req.statement_start_offset / 2) + 1,
                 CASE
                     WHEN req.statement_end_offset > 0
                        THEN (req.statement_end_offset - req.statement_start_offset) / 2
                     ELSE LEN(txt.[text])
                 END
                ) AS [CurrentStatement],
       txt.[text] AS [CurrentBatch],
       CONVERT(XML, qplan.query_plan) AS [StatementQueryPlan],
       OBJECT_NAME(qplan.objectid, qplan.[dbid]) AS [ObjectName],
       sess.[program_name],
       sess.[host_name],
       sess.nt_user_name,
       sess.total_scheduled_time,
       sess.memory_usage,
       req.*
FROM sys.dm_exec_requests req
INNER JOIN sys.dm_exec_sessions sess
        ON sess.session_id = req.session_id
CROSS APPLY sys.dm_exec_sql_text(req.[sql_handle]) txt
OUTER APPLY sys.dm_exec_text_query_plan(req.plan_handle,
                                        req.statement_start_offset,
                                        req.statement_end_offset) qplan
WHERE req.session_id <> @@SPID
ORDER BY req.logical_reads DESC, req.cpu_time DESC
--ORDER BY req.cpu_time DESC, req.logical_reads DESC

Normalerweise führe ich die obige Abfrage so aus, wie sie ist, aber Sie können auch wechseln, welche ORDER BY-Klausel auskommentiert ist, um zu sehen, ob dies interessantere / hilfreichere Ergebnisse liefert.

Alternativ können Sie basierend auf dm_exec_query_stats Folgendes ausführen, um Abfragen mit den höchsten Kosten zu finden. Die erste Abfrage unten zeigt Ihnen einzelne Abfragen (auch wenn sie mehrere Pläne haben) und ist nach durchschnittlicher CPU-Zeit geordnet. Sie können diese jedoch leicht in durchschnittliche logische Lesevorgänge ändern. Wenn Sie eine Abfrage gefunden haben, die anscheinend viele Ressourcen beansprucht, kopieren Sie "sql_handle" und "statement_start_offset" in die WHERE-Bedingung der zweiten Abfrage unten, um die einzelnen Pläne anzuzeigen (kann mehr als 1 sein). Scrollen Sie ganz nach rechts und nehmen Sie an, dass ein XML-Plan vorhanden ist. Dieser wird als Link (im Rastermodus) angezeigt, der Sie zum Plan-Viewer führt, wenn Sie darauf klicken.

Abfrage Nr. 1: Abfrageinformationen abrufen

;WITH cte AS
(
   SELECT qstat.[sql_handle],
          qstat.statement_start_offset,
          qstat.statement_end_offset,
          COUNT(*) AS [NumberOfPlans],
          SUM(qstat.execution_count) AS [TotalExecutions],

          SUM(qstat.total_worker_time) AS [TotalCPU],
          (SUM(qstat.total_worker_time * 1.0) / SUM(qstat.execution_count)) AS [AvgCPUtime],
          MAX(qstat.max_worker_time) AS [MaxCPU],

          SUM(qstat.total_logical_reads) AS [TotalLogicalReads],
   (SUM(qstat.total_logical_reads * 1.0) / SUM(qstat.execution_count)) AS [AvgLogicalReads],
          MAX(qstat.max_logical_reads) AS [MaxLogicalReads],

          SUM(qstat.total_rows) AS [TotalRows],
          (SUM(qstat.total_rows * 1.0) / SUM(qstat.execution_count)) AS [AvgRows],
          MAX(qstat.max_rows) AS [MaxRows]
   FROM sys.dm_exec_query_stats  qstat
   GROUP BY qstat.[sql_handle], qstat.statement_start_offset, qstat.statement_end_offset
)
SELECT  cte.*,
        DB_NAME(txt.[dbid]) AS [DatabaseName],
        SUBSTRING(txt.[text],
                  (cte.statement_start_offset / 2) + 1,
                  CASE
                      WHEN cte.statement_end_offset > 0
                          THEN (cte.statement_end_offset - cte.statement_start_offset) / 2
                      ELSE LEN(txt.[text])
                  END
                 ) AS [CurrentStatement],
        txt.[text] AS [CurrentBatch]
FROM cte
CROSS APPLY sys.dm_exec_sql_text(cte.[sql_handle]) txt
ORDER BY cte.AvgCPUtime DESC

Abfrage Nr. 2: Planinformationen abrufen

SELECT  *,
        DB_NAME(qplan.[dbid]) AS [DatabaseName],
        CONVERT(XML, qplan.query_plan) AS [StatementQueryPlan],
        SUBSTRING(txt.[text],
                  (qstat.statement_start_offset / 2) + 1,
                  CASE
                        WHEN qstat.statement_end_offset > 0
                        THEN (qstat.statement_end_offset - qstat.statement_start_offset) / 2
                        ELSE LEN(txt.[text])
                  END
                 ) AS [CurrentStatement],
        txt.[text] AS [CurrentBatch]
FROM sys.dm_exec_query_stats  qstat
CROSS APPLY sys.dm_exec_sql_text(qstat.[sql_handle]) txt
OUTER APPLY sys.dm_exec_text_query_plan(qstat.plan_handle,
                                        qstat.statement_start_offset,
                                        qstat.statement_end_offset) qplan
-- paste info from Query #1 below
WHERE qstat.[sql_handle] = 0x020000001C70C614D261C85875D4EF3C90BD18D02D62453800....
AND qstat.statement_start_offset = 164
-- paste info from Query #1 above
ORDER BY qstat.total_worker_time DESC

Ich dachte, dass der am höchsten eingestufte Wartetyp aus Pauls Skript, nämlich PREEMPTIVE_OS_DELETESECURITYCONTEXT, die Ursache für die hohe CPU sein könnte. Kann dies in unserem Fall sicher als harmloser Wartetyp angesehen werden? In unserer Anwendung gibt es einige Windows-Dienste, die ständig Befehle (Exec gespeicherte Prozesse) an SQL Server senden. Ich kann nicht zu viele Muster aus sys.dm_exec_sessions erkennen - Sitzungen bleiben nicht zu lange geöffnet und es gibt viele davon. sys.dm_exec_query_stats bietet einige gute Informationen zu den teuersten gespeicherten Prozessen, was die Gesamtkosten der CPU betrifft. Dies kann ein guter Anfang sein.
John Russell

Ich wollte nur sicherstellen, dass mir mit PREEMPTIVE_OS_DELETESECURITYCONTEXT nichts entgeht. Ich wusste nicht, ob dies auf einen fehlerhaften Domänencontroller oder AD-Lookups zurückzuführen ist.
John Russell

@JohnRussell: Ich denke, der höchste Wartetyp ist normalerweise ein guter Ausgangspunkt, aber mein Punkt ist, dass dieser bestimmte Typ nicht nur durch Code in SQL Server ausgelöst wird, der auf externe Ressourcen wie Linked Server oder SQLCLR oder erweiterte gespeicherte Prozesse (z xp_dirtree), daher ist eine hohe Lautstärke kein echter Indikator. Und selbst wenn Netzwerklatenz Verzögerungen verursacht, würde dies die CPU wirklich erhöhen oder nur die Blockierung erhöhen? Und guter Punkt, verwenden Sie query_stats. Ich werde meine Anfrage später damit aktualisieren.
Solomon Rutzky

1
@ JohnRussell: In Bezug auf Ihre "Windows-Dienste, die ständig Befehle senden", hat sich in letzter Zeit etwas geändert? Schließen sie die Verbindungen ordnungsgemäß? Bereinigen sie die Verbindung ordnungsgemäß, wenn während der Verbindung ein Fehler auftritt? Haben Sie kürzlich Indizes neu erstellt oder zumindest die Statistiken für alle Tabellen aktualisiert? Wenn Sie dies nicht tun, kann dies zu einer Erhöhung der CPU führen.
Solomon Rutzky

Danke für den Einblick! Wenn ich mir sys.dm_exec_query_stats und die Indexfragmentierung einiger Schlüsseltabellen genauer ansehe, fühle ich mich zunehmend sicherer in Bezug auf die Ursache. PREEMPTIVE_OS_DELETESECURITYCONTEXT hat mich einfach umgehauen.
John Russell

1

Der SecurityContext wird vom SQL Server an mehreren Stellen verwendet. Ein Beispiel, das Sie benannt haben, sind die Verbindungsserver und Dateitabellen. Vielleicht verwenden Sie cmdexec? SQL Server Agent-Jobs mit Proxy-Konten? Einen Webservice anrufen? Remote-Ressourcen können viele lustige Dinge sein.

Identitätswechselereignisse können im Windows-Sicherheitsereignis protokolliert werden. Es könnte sein, dass Sie dort einen Hinweis finden. Außerdem möchten Sie vielleicht den Blackbox-Rekorder überprüfen, auch bekannt als erweiterte Ereignisse.

Haben Sie überprüft, ob diese Wartetypen neu (und in Verbindung mit der hohen CPU) oder nur normal für Ihren Server sind?


Wir haben weder SQL Server Agent-Jobs noch WebServices. Ich habe die Wartestatistiken gelöscht und die ursprüngliche Abfrage oben erneut ausgeführt, und ähnliche Statistiken werden erneut angezeigt. Ich brauchte ein wenig, um herauszufinden, wie ich die erweiterte Ereignissitzung system_health so konfigurieren konnte, dass wait_info_external für waittype = 'PREEMPTIVE_OS_DELETESECURITYCONTEXT' enthalten ist, aber ich habe es endlich hinzugefügt. Ich kann Hunderte dieser Ereignisse in den wenigen Sekunden sehen, in denen ich die Live-Daten beobachtete . Ich suche nach einer besseren Entschlüsselung der Quelle. Irgendwelche Ratschläge, wie man das aufspürt?
John Russell
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.