web-dev-qa-db-ja.com

より多くのCPUおよびRAMを割り当てた後、SQL Serverのパフォーマンスが低下する

SQL Server 2008 R2(10.50.1600)が仮想Windows 2008 R2サーバーで実行されています。 CPUを1コアから4にアップグレードし、RAMを4 GBから10 GBにアップグレードした後、パフォーマンスが低下していることがわかりました。

私が見るいくつかの観察:

  1. 実行に5秒未満かかったクエリは、現在200秒以上かかっています。
  2. CPUは、犯人としてsqlservr.exeが100に固定されています。
  3. 460万行のテーブルでの選択カウント(*)には90秒以上かかりました。
  4. サーバー上で実行されているプロセスは変更されていません。唯一の変更は、CPUとRAMを増やすことでした。
  5. 他のSQLサーバーには、このサーバーが独自に管理するように設定されている静的ページングファイルがあります。

誰かが以前にこの問題に遭遇したことがありますか?

Sp_BlitzErikごとに、私は実行しました

EXEC dbo.sp_BlitzFirst @SinceStartup = 1;

私にこれらの結果を与えます。

wait stats

33
Jeff

ここでは多くのことが起こっており、そのほとんどはかなり広範で曖昧です。

  1. 2008R2 RTM 2010年4月21日にリリースされました。完全にサポート対象外です。約3年前にリリースされた最新のService Packを優先して利用することをお勧めします。そうすれば、奇妙なバグや何かにぶつかったときにカバーされます。ダウンロードする必要があるものを理解するには、 over here に進んでください。

  2. VCPU(1から4)を追加し、設定を変更しなかったため、クエリを並列処理できます。これらはすべて速くなるように聞こえますが、しばらくお待ちください!

  3. RAMを追加した可能性がありますが、サーバーがそれを利用できるように最大サーバーメモリを変更していない可能性があります。

  4. サーバーが待機しているものを把握します。私が取り組んでいるオープンソースプロジェクトには、SQL Serverの測定に役立つ無料のスクリプトが用意されています。 over here を試してみてください。

サーバーの待機統計を確認するには、sp_BlitzFirstを取得します。いくつかの方法で実行できます。

これにより、サーバーが起動してから何が待機していたかがわかります。

EXEC dbo.sp_BlitzFirst @SinceStartup = 1;

これにより、30秒のウィンドウの間に、現在どのクエリが待機しているかが表示されます。

EXEC dbo.sp_BlitzFirst @Seconds = 30, @ExpertMode = 1;

どのクエリが待機しているのかがわかったら(待機統計について大量のものが書かれています)、変更を加えて制御を開始できます。

それらがCXPACKETで待機しているのを見る場合、それはクエリが並列になり、おそらく相互に踏みつけていることを意味します。これに達した場合は、並列処理のコストしきい値を最大50に上げ、MAXDOPを2に下げることを検討することをお勧めします。

このステップの後は、クエリプランのキャプチャを開始するために sp_WhoIsActive またはsp_BlitzWho(後者は前のGitHubリポジトリにあります)のようなものを使用したい場合です。待機統計は別として、何が問題なのかを理解するために見ることができる最も重要なものの1つです。

また、SQL Serverに関連してチェックアウトする VMWare Counters について、Jonathan Kehayiasによるこの記事をチェックすることもできます。

更新

彼らは奇妙な待機統計と少年を確認します。 CPUには間違いなく何か問題があります。サーバーはほとんど退屈ですが、物事が熱くなると物事が悪化します。簡単に分解してみます。

  1. THREADPOOLと呼ばれる poison wait を実行しています。それほど多くはありませんが、サーバーがひどくアクティブではないので、それは理にかなっています。その理由をすぐに説明します。

  2. SOS_SCHEDULER_YIELDCXPACKETの平均待機時間が非常に長くなっています。 VMを使用しているので、SQL Serverが予約されていること、またはボックスがひどくオーバーサブスクライブされていないことを確認します。騒々しい隣人はここであなたの一日を本当に台無しにすることができます。また、サーバー/ VMゲスト/ VMホストが平衡電力モードで実行されていないことを確認する必要もあります。これにより、CPUが不必要に低速にスピンダウンし、すぐにフルスピードに戻りません。

  3. 彼らはどのように結びつきますか? 4 CPUの場合、512のワーカースレッドがあります。単一のCPUで 同量 を使用していたことを覚えておいてください。ただし、クエリを並列処理できるようになったため、より多くのワーカースレッドを消費する可能性があります。あなたのケースでは、並列クエリの並列ブランチごとに4つのスレッド。

何が並行するのですか?ほとんどの場合。並列処理のデフォルトのコストしきい値は5です。この数値は、90年代後半のある時点で like this のように見えるデスクトップで作業しているときにデフォルトになりました。

NUTS

確かに、ハードウェアはほとんどのラップトップよりも小さいですが、それでもまだ少し先んじています。

多数の並列クエリが実行されると、それらのワーカースレッドが不足します。その場合、クエリはスレッドが実行されるのを待つだけです。 SOS_SCHEDULER_YIELDの出番でもあります。クエリはCPUから離れており、長い間戻ってきません。ブロッキングの待機は見当たらないので、クエリ内並列処理の待機がすべて詰まっている可能性があります。

あなたは何ができますか?

  1. バランスパワーモードに何もないことを確認します
  2. MAXDOPを2に変更します
  3. 並列処理のコストしきい値を50に変更
  4. 上記のJon K.の記事に従って、VM healthを検証します
  5. sp_BlitzIndexというスクリプトを使用して、欠落しているインデックスリクエストを探します。

より完全なトラブルシューティングについては、クラウドでのハードウェアのサイジングについて Google向けに書いたホワイトペーパー を確認してください。

お役に立てれば!

55
Erik Darling

はい!サーバーファームのSQL Server VMでこのような状況を経験しました。 VMのホストCPU準備時間とメモリバルーンドライバーカウンターを確認します。 CPU READY TIME – BLOG PART I および VMware Ballooningについて システム管理者との連携が重要でしたが、簡単ではありませんでした...

8

私が指摘しなかった1つのことは、vCPUをVMに追加すると、スケジューリングが原因で非常に頻繁に遅くなる可能性があることです。

基本的な考え方は、VMに4つのvCPUがある場合、ハイパーバイザーは4つの物理コアが使用可能になるまで待機する必要があるため、3つがアイドル状態であってもすべてのvCPUをスケジュールできます。

ホストにコアが多くなく、他のワークロードがビジーである場合、これにより待機時間が長くなり、パフォーマンスが大幅に低下する可能性があります。

VMware ESXiでは、CPU Readyを介して詳細グラフで確認できます。

これが実際に起こっていることの例とそれがどのように診断されたかを示す多くの記事の1つです

さらにRAMを追加すると、VMのRAM割り当てがNUMAノードよりも大きい場合、パフォーマンスが突然低下する可能性があります。

さらに、vCPU(vSocketsとvCores)の構成は、SQLサーバーなどの一部のアプリケーションに実際に影響を与える可能性があります。これは、SQLサーバー自体がNUMA対応であるため(同じ種類のNUMA全体のパフォーマンス低下を回避するため)、VMwareが仮想NUMAノードを異なる方法で表示する可能性があるためです。

これはVMware自身のサイトのブログ投稿でカバーされています


そうは言っても、Erikの助けを借りて問題を解決できてうれしいですが、これらのことも調べて検討したいと思うかもしれません。

5
briantist

@sp_BlitzErikの答えを続けるだけの少しのヘルプ(これをコメントとして投稿することはできません)で、使用するMAXDOPの量を示すいくつかのクエリをPinalとMax Vernon(rememebr whereはできません)で取得しました。

/*************************************************************************
Author          :   Kin Shah
Purpose         :   Recommend MaxDop settings for the server instance
Tested RDBMS    :   SQL Server 2008R2

**************************************************************************/
declare @hyperthreadingRatio bit
declare @logicalCPUs int
declare @HTEnabled int
declare @physicalCPU int
declare @SOCKET int
declare @logicalCPUPerNuma int
declare @NoOfNUMA int

select @logicalCPUs = cpu_count -- [Logical CPU Count]
    ,@hyperthreadingRatio = hyperthread_ratio --  [Hyperthread Ratio]
    ,@physicalCPU = cpu_count / hyperthread_ratio -- [Physical CPU Count]
    ,@HTEnabled = case 
        when cpu_count > hyperthread_ratio
            then 1
        else 0
        end -- HTEnabled
from sys.dm_os_sys_info
option (recompile);

select @logicalCPUPerNuma = COUNT(parent_node_id) -- [NumberOfLogicalProcessorsPerNuma]
from sys.dm_os_schedulers
where [status] = 'VISIBLE ONLINE'
    and parent_node_id < 64
group by parent_node_id
option (recompile);

select @NoOfNUMA = count(distinct parent_node_id)
from sys.dm_os_schedulers -- find NO OF NUMA Nodes 
where [status] = 'VISIBLE ONLINE'
    and parent_node_id < 64

-- Report the recommendations ....
select
    --- 8 or less processors and NO HT enabled
    case 
        when @logicalCPUs < 8
            and @HTEnabled = 0
            then 'MAXDOP setting should be : ' + CAST(@logicalCPUs as varchar(3))
                --- 8 or more processors and NO HT enabled
        when @logicalCPUs >= 8
            and @HTEnabled = 0
            then 'MAXDOP setting should be : 8'
                --- 8 or more processors and HT enabled and NO NUMA
        when @logicalCPUs >= 8
            and @HTEnabled = 1
            and @NoofNUMA = 1
            then 'MaxDop setting should be : ' + CAST(@logicalCPUPerNuma / @physicalCPU as varchar(3))
                --- 8 or more processors and HT enabled and NUMA
        when @logicalCPUs >= 8
            and @HTEnabled = 1
            and @NoofNUMA > 1
            then 'MaxDop setting should be : ' + CAST(@logicalCPUPerNuma / @physicalCPU as varchar(3))
        else ''
        end as Recommendations

-------------------------------------------------- -------

--MAX VERNON 

/* 
   This will recommend a MAXDOP setting appropriate for your machine's NUMA memory
   configuration.  You will need to evaluate this setting in a non-production 
   environment before moving it to production.

   MAXDOP can be configured using:  
   EXEC sp_configure 'max degree of parallelism',X;
   RECONFIGURE

   If this instance is hosting a Sharepoint database, you MUST specify MAXDOP=1 
   (URL wrapped for readability)
   http://blogs.msdn.com/b/rcormier/archive/2012/10/25/
   you-shall-configure-your-maxdop-when-using-sharepoint-2013.aspx

   Biztalk (all versions, including 2010): 
   MAXDOP = 1 is only required on the BizTalk Message Box
   database server(s), and must not be changed; all other servers hosting other 
   BizTalk Server databases may return this value to 0 if set.
   http://support.Microsoft.com/kb/899000
*/
SET NOCOUNT ON;

DECLARE @CoreCount int;
SET @CoreCount = 0;
DECLARE @NumaNodes int;

/*  see if xp_cmdshell is enabled, so we can try to use 
    PowerShell to determine the real core count
*/
DECLARE @T TABLE (
    name varchar(255)
    , minimum int
    , maximum int
    , config_value int
    , run_value int
);
INSERT INTO @T 
EXEC sp_configure 'xp_cmdshell';
DECLARE @cmdshellEnabled BIT;
SET @cmdshellEnabled = 0;
SELECT @cmdshellEnabled = 1 
FROM @T
WHERE run_value = 1;
IF @cmdshellEnabled = 1
BEGIN
    CREATE TABLE #cmdshell
    (
        txt VARCHAR(255)
    );
    INSERT INTO #cmdshell (txt)
    EXEC xp_cmdshell 'powershell -OutputFormat Text -NoLogo -Command "& {Get-WmiObject -namespace "root\CIMV2" -class Win32_Processor -Property NumberOfCores} | select NumberOfCores"';
    SELECT @CoreCount = CONVERT(INT, LTRIM(RTRIM(txt)))
    FROM #cmdshell
    WHERE ISNUMERIC(LTRIM(RTRIM(txt)))=1;
    DROP TABLE #cmdshell;
END
IF @CoreCount = 0 
BEGIN
    /* 
        Could not use PowerShell to get the corecount, use SQL Server's 
        unreliable number.  For machines with hyperthreading enabled
        this number is (typically) twice the physical core count.
    */
    SET @CoreCount = (SELECT i.cpu_count from sys.dm_os_sys_info i); 
END

SET @NumaNodes = (
    SELECT MAX(c.memory_node_id) + 1 
    FROM sys.dm_os_memory_clerks c 
    WHERE memory_node_id < 64
    );

DECLARE @MaxDOP int;

/* 3/4 of Total Cores in Machine */
SET @MaxDOP = @CoreCount * 0.75; 

/* if @MaxDOP is greater than the per NUMA node
    Core Count, set @MaxDOP = per NUMA node core count
*/
IF @MaxDOP > (@CoreCount / @NumaNodes) 
    SET @MaxDOP = (@CoreCount / @NumaNodes) * 0.75;

/*
    Reduce @MaxDOP to an even number 
*/
SET @MaxDOP = @MaxDOP - (@MaxDOP % 2);

/* Cap MAXDOP at 8, according to Microsoft */
IF @MaxDOP > 8 SET @MaxDOP = 8;

PRINT 'Suggested MAXDOP = ' + CAST(@MaxDOP as varchar(max));
3
Racer SQL