SQL Serverのパフォーマンス:PREEMPTIVE_OS_DELETESECURITYCONTEXT主要な待機タイプ


8

昨日、SQL ServerのCPU使用率が高いことについて不満を言っていた顧客から電話がありました。SQL Server 2012 64ビットSEを使用しています。サーバーはWindows Server 2008 R2 Standard、2.20 GHz Intel Xeon(4コア)、16 GB RAMを実行しています。

犯人が実際にSQL Serverであることを確認した後、ここで DMVクエリを使用してインスタンスの上位の待機を調べました。上位2つの待機は(1)PREEMPTIVE_OS_DELETESECURITYCONTEXTと(2)SOS_SCHEDULER_YIELDでした。

編集:「トップ待機クエリ」の結果を次に示します(誰かが私の希望に反して今朝サーバーを再起動しましたが)。

ここに画像の説明を入力してください

私たちは多くの激しい計算/変換を行うので、私は理解できますSOS_SCHEDULER_YIELD。しかし、私はPREEMPTIVE_OS_DELETESECURITYCONTEXT待機タイプとそれが最も高い理由について非常に興味があります。

この待機タイプについて私が見つけることができる最良の説明/ディスカッションは、ここにあります。それは言及しています:

PREEMPTIVE_OS_待機タイプは、データベースエンジン(通常はWin32 API)を離れ、さまざまなタスクのためにSQL Serverの外部でコードを実行する呼び出しです。この場合、以前にリモートリソースアクセスに使用されていたセキュリティコンテキストが削除されています。関連するAPIは、実際にはDeleteSecurityContext()という名前です

私の知る限り、リンクサーバーやファイルテーブルなどの外部リソースはありません。また、なりすましなどは一切行いません。バックアップが原因でスパイクが発生したり、ドメインコントローラに障害が発生したりする可能性はありますか?

これが主な待機タイプになる原因は何ですか?この待機タイプをさらに追跡するにはどうすればよいですか?

編集2: Windowsセキュリティログの内容を確認しました。興味のあるエントリがいくつかありますが、これらが正常かどうかはわかりません。

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

編集3:@Jon Seigelがリクエストしたとおり、ここにクエリの結果があります。ポールとは少し違う:

ここに画像の説明を入力してください

編集4:私は認めます、私は初めて拡張イベントのユーザーです。この待機タイプをwait_info_externalイベントに追加し、数百のエントリを確認しました。SQLテキストまたはプランハンドルはなく、呼び出しスタックのみです。ソースをさらに追跡するにはどうすればよいですか?

ここに画像の説明を入力してください


ジョン、一定期間(おそらく1分)sp_whoisactiveを実行して、何がポップアップするかを確認してください。これはあなた/私たちを解決策に導くのを助けるかもしれません。sqlblog.com/files/default.aspx
Mark Wilkinson、

こんにちは、ジョン、あなたの質問では、SQL Serverを犯人として特定したことについて述べています。その結論に至るために取った手順を教えてください。
Craig Efrein 2014年

回答:


3

この質問は、タイトルに基づいて、主にPREEMPTIVE_OS_DELETESECURITYCONTEXT待機タイプに関係していることを知っていますが、それは「SQL ServerでのCPU使用率の高さについて不平を言っていた顧客という本当の問題の誤解だと思います

この特定の待機タイプに焦点を合わせることが野生のガチョウ追跡であると私が思う理由は、接続が確立されるたびに上がるためです。私のラップトップで次のクエリを実行しています(つまり、私が唯一のユーザーです)。

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

次に、次のいずれかを実行して、このクエリを再実行します。

  • 新しいクエリタブを開く
  • 新しいクエリタブを閉じます
  • DOSプロンプトから次のコマンドを実行します。 SQLCMD -E -Q "select 1"

これで、CPUの使用率が高いことがわかったので、何が実行されているかを調べて、CPUの使用率が高いセッションを確認する必要があります。

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

通常は上記のクエリをそのまま実行しますが、コメント化されているORDER BY句を切り替えて、より興味深い/役立つ結果が得られるかどうかを確認することもできます。

または、dm_exec_query_statsに基づいて次のコマンドを実行して、最もコストの高いクエリを見つけることもできます。以下の最初のクエリは、個々のクエリ(複数のプランがある場合でも)を示し、平均CPU時間順に並べられていますが、平均論理読み取りに簡単に変更できます。大量のリソースを使用しているように見えるクエリを見つけたら、「sql_handle」と「statement_start_offset」を以下の2番目のクエリのWHERE条件にコピーして、個々のプランを確認します(1以上になる場合があります)。右端までスクロールすると、XMLプランがあったとすると、それが(グリッドモードで)リンクとして表示され、クリックするとプランビューアーに移動します。

クエリ#1:クエリ情報を取得する

;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

クエリ#2:プラン情報を取得する

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

Paulのスクリプトで最もランクの高い待機タイプ、つまりPREEMPTIVE_OS_DELETESECURITYCONTEXTが、CPU使用率が高い原因であると考えました。私たちの場合、これは無害な待機タイプと考えることができますか?このアプリケーションでは、SQL Serverにコマンド(exec stored procs)を常に送信しているいくつかのWindowsサービスがあります。sys.dm_exec_sessionsからあまりにも多くのパターンを識別できません-セッションが長時間開いたままにならず、それらのパターンがたくさんあります。sys.dm_exec_query_statsは、全体的なCPUコストに関する限り、最も高価なストアドプロシージャに関する優れた情報を提供します。ここから始めるのが良いでしょう。
ジョンラッセル

PREEMPTIVE_OS_DELETESECURITYCONTEXTで何かが欠落していないことを確認したかっただけです。これが障害のあるドメインコントローラーまたはADルックアップに追跡できるかどうか知りませんでしたか?
ジョンラッセル

@JohnRussell:通常、最も高い待機タイプは開始するのに最適な場所だと思いますが、私の特定の点は、リンクサーバーやSQLCLRなどの外部リソースにアクセスするSQL Server内のコードや拡張ストアドプロシージャ(たとえば、 xp_dirtree)、したがって、ボリュームが大きいことは真のインジケータではありません。また、遅延の原因となるネットワークレイテンシがあったとしても、それによって本当にCPUが向上するのでしょうか、それとも単にブロックが増えるのでしょうか。そして良い点は、query_statsを使用することです。後でクエリを更新します。
ソロモンルツキー2014年

1
@JohnRussell:「常にコマンドを送信しているWindowsサービス」に関して、最近何か変わったことはありますか?接続を適切に閉じていますか?接続中にエラーが発生した場合、接続を適切にクリーンアップしますか?また、最近インデックスを再構築したか、少なくともすべてのテーブルの統計を更新したか?これらを実行しないと、CPUが増加する可能性があります。
ソロモンRutzky 14年

洞察をありがとう!いくつかの主要なテーブルでsys.dm_exec_query_statsとインデックスの断片化を詳しく見ていくと、原因に自信がつき始めています。PREEMPTIVE_OS_DELETESECURITYCONTEXTが私を解雇しました。
John Russell

1

SecurityContextは、SQLサーバーによっていくつかの場所で使用されます。名前を付けた1つの例は、リンクサーバーとファイルテーブルです。多分あなたはcmdexecを使っていますか?プロキシアカウントを使用したSQL Serverエージェントジョブ?Webサービスを呼び出しますか?リモートリソースは、面白いことがたくさんあります。

偽装イベントは、Windowsセキュリティイベントに記録できます。あなたはそこに手掛かりを見つけているかもしれません。さらに、ブラックボックスレコーダー、つまり拡張イベントを確認することもできます。

これらの待機タイプが新しい(または高CPUに関連する)ものか、サーバーにとって通常のものかを確認しましたか?


SQL ServerエージェントジョブもWebサービスもありません。私は待機統計をクリアし、上記の元のクエリを再実行し、同様の統計が再出現しました。system_health拡張イベントセッションを再構成してwaittype = 'PREEMPTIVE_OS_DELETESECURITYCONTEXT'のwait_info_externalを含める方法を理解するには少し時間がかかりましたが、ついに追加されました。ライブデータを監視していた数秒で数百のイベントを確認できます。ソースをよりよく解読する方法を探しています。これを追跡する方法に関するアドバイスはありますか?
John Russell、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.