SQL Serverのパフォーマンスの突然の低下


13

最近、予測不能になったSQL Server 2005があり、その理由について頭を悩ませています。数秒で実行されるクエリは、計画を変更し、数分かかります(フルテーブルスキャンまたはインデックススプールに時間がかかります)。最初の最も明白なことは、統計が古くなってオプティマイザーが混乱することですが、これはそうではないと確信しています-まず、基礎となるデータが大きく変化していないためです2番目に、統計の自動作成と統計の自動更新が両方とも真であるためです。ただし、オプティマイザー混乱しています。チューニングアドバイザーでSQLを実行CREATE STATISTICSすると、(次のSQLが誤動作するまで)修正しているように見える複数列のステートメントが多数得られます。

これを根本原因とするアプローチに使用できる戦略のアイデアはありますか?「通常の」統計だけでは不十分な理由はありますか?

回答:


8

上位の待機がSOS_SCHEDULER_YIELDの場合、CPUにプレッシャーがかかっているように見えます。しかし、これは、デザインがクエリに対して十分ではなくなったなど、他の何かの結果である可能性があります。1日分のデータだけを追加していると言っていましたが、転換点に達する可能性がありました。

クエリはどのように発行されますか?動的SQLですか?ストアドプロシージャを使用していますか?sp_executesqlを使用していますか?パラメータースニッフィングのケースがある可能性はありますか?DBの設計はどのように見えますか?PKとFKの関係は何ですか?

良い計画の例はありますか?適切なプランを決定できる場合は、プランガイドを使用して、特定の方法でクエリを強制的に実行できます。

悪くなった良い計画の例を挙げていただけますか?

最後に、Adam Machanicからsp_whoIsActive(http://whoisactive.com/)のコピーを取得し、それを使用して実行中のクエリの詳細を判断します。また、sp_whoIsActiveからの出力をキャプチャできるようにするには、http://www.littlekendra.com/2011/02/01/whoisactive/にアクセスしてください。


これはサードパーティのアプリケーションです。スキーマやSQLを制御することはできません。これは非常に恐ろしく、多くのパラメーター化されたクエリ(例where col=(cast @var...))であり、私は1〜2週間前にそれを継承しましたが、交換されるまで基本的に機能し続ける必要があります。リンクをお寄せいただきありがとうございます。@var'%'
ガイウス

次の最大の待ち時間SOS_SCHEDULER_YIELDCXPACKETsp_configure "max degree of parallelism", 1今のところ-両方の問題を頭の上でノックしていたようです。ありがとう!
ガイウス

sp_whoIsActiveへのリンクのための1
ジェフ

8

MSDNから:

挿入操作昇順または降順キー列で発生し 、このようなIDENTITYやリアルタイムのタイムスタンプ列としてキー列を、昇順または降順に統計、クエリオプティマイザが実行するよりも、より頻繁に統計情報の更新が必要な場合があります。挿入操作が列を昇順または降順に新しい値を追加統計が最新ではなく、クエリが最後に追加された行から選択した場合、現在の統計にはこれらの新しい値のカーディナリティの推定値が含まれません。カーディナリティの推定値が不正確になり、クエリのパフォーマンスが低下します。

たとえば、統計が最新の受注日のカーディナリティ推定値を含むように更新されない場合、最新の受注日付から選択するクエリは不正確なカーディナリティ推定値を持ちます。

メンテナンス操作後 後テーブルの切り捨てや行の大部分の一括挿入の実行など、データの分布を変更するメンテナンス手順を実行した後、統計の更新を検討してください。これにより、クエリが統計の自動更新を待つ間、クエリ処理の将来の遅延を回避できます。」

システムで時々「EXEC sp_updatestats」を使用するか(スケジュールされている)、すべてのオブジェクトで関数STATS_DATEを使用して、前回統計が実際に更新された時期を確認し、それ以降時間が長すぎる場合は、UPDATEを使用しますその特定のオブジェクトの統計。私の経験では、自動統計を有効にしても、自動更新をトリガーしなかった挿入操作のために、時々統計を更新する必要があります。

私の個人コードを追加するには(統計更新用の動的ステートメントを作成する毎週のジョブで使用):

select distinct
        'update statistics [' + stats.SchemaName + '].[' + stats.TableName + ']'
            + case when stats.RowCnt > 50000 then ' with sample 30 percent;'
            else 
                ';' end
        as UpdateStatement
    from (
        select
            ss.name SchemaName,
            so.name TableName,
            so.id ObjectId,
            st.name AS StatsName, 
            STATS_DATE(st.object_id, st.stats_id) AS LastStatisticsUpdateDate
            , si.RowModCtr
            , (select case si2.RowCnt when 0 then 1 else si2.RowCnt end from sysindexes si2 where si2.id = si.id and si2.indid in (0,1)) RowCnt
        from sys.stats st
            join sysindexes si on st.object_id = si.id and st.stats_id = si.indid
            join sysobjects so on so.id = si.id and so.xtype = 'U' --user table
            join sys.schemas ss on ss.schema_id = so.uid
    ) stats
    where cast(stats.RowModCtr as float)/cast(stats.RowCnt as FLOAT)*100 >= 10 --more than 10% of the rows have changed
    or ( --update statistics that were not updated for more than 3 months (and rows no > 0)
        datediff(month, stats.LastStatisticsUpdateDate, getdate()) >= 3
        and stats.RowCnt > 0
    )

ここでは、3か月以上統計が更新されていない、または最後の統計が更新されてから10%を超える行が変更されたすべてのオブジェクトを取得します。


うーん、私の一番上の待機イベントはSOS_SCHEDULER_YIELD、それが悪い計画によるものなのか、この(6歳、2プロセッサー、4G RAM)ボックスが本当に過負荷になったのか、今はわからないいくつかの転換点を超えました。
ガイウス

そのクエリを実行してUPDATEステートメントを作成し、それらを手動で実行するのではなく、そのselectステートメントに基づいてカーソルを使用して、sp_executesqlの呼び出しを使用して実行結果をループ処理することができます-その方法で(たとえば、一部として)一晩(または他の静かな期間)メンテナンス計画の)。
デビッドスピレット

@David:これは私が毎週の仕事でやっていることです:)。Gaiusが使用している出力を確認できるように、フォーマットを変更しました。最初のスクリプトはwayくて長すぎました。フォーマットに関するヘルプをありがとう!ここでコードを見栄えよくする方法が本当にわからないので、フォーマットチュートリアルを送ってもらえますか。ありがとう!
マリアン

「回答の編集」画面には「書式設定ヘルプ」リンクがあり、メインの質問ページの最初の回答ボックスの右上にあるアイコンとして、これらのサイトでサポートされているマークダウン構文がリストされています。
デビッドスピレット

3
自動更新統計は、実際には10%ではなく20%+ 500行でトリガーされます。
-mrdenny

3

私の推測では、1つ以上のテーブルが十分に大きくなり、現在の統計を失効としてマークするのに必要な20%の変更に達していないため、自動更新統計が有効になり、まだ十分な更新(または挿入)があります)統計を更新することは大いに役立ちます。SQL 2000からSQL 2008にアップグレードした後、特定の環境で最近同じことを発見しました。

上記の回答で言及した他のサイトに加えて、次のオンラインリソースを確認することをお勧めします。

1)Red-Gateには、Holger Schmelingによる「SQL Server Statistics」など、ダウンロード可能な無料の電子書籍が多数あります。ここには、次の引用があります。

http://www.red-gate.com/our-company/about/book-store/

「リンクされた統計を無効にするには、列のデータの少なくとも20%が500行を超えるテーブルを変更する必要がありました」

2)SQL Sentryには、SQLプラン内の問題(クエリ内の特定のテーブルの実際の行数と比較した行数が多すぎる、または少なすぎるなど)を追跡するのに役立つ無料のプランエクスプローラーツールがあります。SSMSから実際の実行計画を保存し、Plan Explorerを使用して計画のさまざまな部分をウォークスルーするだけです。グラフィック実行プランを使用してSSMSで情報を利用できないわけではありませんが、SQL Sentryのツールを使用すると、見やすくなります。

http://www.sqlsentry.com/plan-explorer/sql-server-query-view.asp

3)STATS_DATE()を使用して最も関心のあるクエリのテーブルの統計更新日を自分でチェックします。次の説明にあるクエリを使用して、最も古い統計を取得するクイッククエリを見つけることができます。

http://blog.sqlauthority.com/2010/01/25/sql-server-find-statistics-update-date-update-statistics/

これがお役に立てば幸いです!

Red-Gateの本は特にお楽しみいただけると思います!

-ジェフ


おかげで、私はそれらを通して私の方法を動作させます。私は主にこのシステムを継承したOracle DBAです(そうです、SQL Serverに偏見はありません。2005年以来、非常に有能なプラットフォームだからです。 。
ガイウス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.