強力なサーバーでSQL Server 2014を実行する約1TBの大規模なデータベースがあります。すべてが数年間問題なく動作しました。約2週間前に、次のような完全なメンテナンスを行いました。すべてのソフトウェアアップデートをインストールします。すべてのインデックスとコンパクトDBファイルを再構築します。ただし、実際の負荷が同じ場合、特定の段階でDBのCPU使用率が100%から150%増加するとは予想していませんでした。
多くのトラブルシューティングの後、非常に単純なクエリに絞り込みましたが、解決策を見つけることができませんでした。クエリは非常に簡単です。
select top 1 EventID from EventLog with (nolock) order by EventID
常に約1.5秒かかります。ただし、 "desc"を使用した同様のクエリは常に約0ミリ秒かかります。
select top 1 EventID from EventLog with (nolock) order by EventID desc
PTableには約5億行あります。 EventID
は、bigint(Identity列)のデータ型を持つプライマリクラスター化インデックス列(ASC
の順序)です。上部のテーブルにデータを挿入する複数のスレッドがあり(大きいイベントID)、下部からデータを削除する1つのスレッドがあります(小さいイベントID)。
SMSSでは、2つのクエリが常に同じ実行プランを使用することを確認しました。
クラスター化インデックススキャン。
推定および実際の行番号はどちらも1です。
推定実行数と実際の実行数はどちらも1です。
推定I/Oコストは8500(高いようです)
連続して実行した場合、クエリのコストは両方で同じ50%です。
インデックス統計を更新しましたwith fullscan
、問題が解決しませんでした。インデックスを再構築したところ、問題は半日消えたようですが、戻ってきました。
IO統計をオンにしました:
set statistics io on
次に、2つのクエリを連続して実行し、次の情報を見つけました。
(最初のクエリの場合、遅いクエリ)
テーブル「PTable」。スキャンカウント1、論理読み取り407670、物理読み取り0、先読み読み取り0、LOB論理読み取り0、LOB物理読み取り0、LOB先読み読み取り0。
(2番目のクエリは高速です)
テーブル「PTable」。スキャンカウント1、論理読み取り4、物理読み取り0、先読み読み取り0、LOB論理読み取り0、LOB物理読み取り0、LOB先読み読み取り0。
論理読み取りの大きな違いに注意してください。インデックスはどちらの場合にも使用されます。
インデックスの断片化は少し説明しますが、影響は非常に小さいと思います。そして問題は前に起こったことはありません。別の証拠は、次のようなクエリを実行した場合です。
select * from EventLog with (nolock) where EventID=xxxx
Xxxxをテーブル内の最小のEventIDに設定しても、クエリは常に非常に高速です。
確認しましたが、ロック/ブロックの問題はありません。
注:上記の問題を単純化しようとしました。 「PTable」は実際には「EventLog」です。 PID
はEventID
です。
NOLOCK
ヒントなしで同じ結果のテストを取得します。
誰か助けてもらえますか?
XMLによるより詳細なクエリ実行プランは次のとおりです。
https://www.brentozar.com/pastetheplan/?id=SJ3eiVnob
https://www.brentozar.com/pastetheplan/?id=r1rOjVhoZ
Create tableステートメントを提供することは重要ではないと思います。これは古いデータベースであり、メンテナンスまで長い間完全に問題なく稼働しています。私たちは自分たちで多くの調査を行い、それを私の質問で提供された情報に絞り込みました。
テーブルは通常、EventID
列を主キーとして作成されました。これは、identity
タイプのbigint
列です。現時点では、問題はインデックスの断片化にあると思います。インデックスの再構築直後、問題は半日消えたようです。なぜこんなに早く戻ってきたのか...?
クラスタ化インデックススキャンは、1926ミリ秒かかって最初の行を返す423,723の論理読み取りを示しています。
これは、最初の行をインデックス順に配置するのにかなりかかります。
ゴーストクリーンアップタスクが大幅に遅れているか、停止している可能性があります。 ghost_record_count
sys.dm_db_index_physical_stats
と経時変化を監視します。
一定の削除アクティビティが発生しているインデックスの最後からの順序付きスキャンは、最初の 'aliveを見つける前に、非常に多くのゴーストレコードをスキャンする必要があります。 '返す行。これは、余分な論理読み取りを説明します。 Bツリーをインデックスの最も低い値までシークすると、ゴースト化されたレコードがはるかに少なくなります。
パフォーマンスに影響を与えるもう1つの要因は、Paul Randalによる ストレージエンジンの内部:ゴーストクリーンアップの詳細 で説明されているように、スキャン自体がゴーストレコードの削除を担当することです。
トレースフラグ661(ゴーストクリーンアップを無効にする)がアクティブでないことを確認する必要があります。
PAGLOCK
ヒントを使用するように変更します その場でゴーストクリーンアップを有効にします 。これも問題を解決できます。ゴーストクリーンアッププロセスが完全に停止した場合、最も効果的な解決策は、通常、SQL Serverインスタンスを再起動することです。また、SQL Serverが最新の累積的な更新の1つを実行していることを確認する必要もあります。長年にわたって多くのゴーストクリーンアップバグがありました。
あなたの特定のケースでは:
問題は同じサーバー上の別のテストデータベースが原因であることが判明しました。そのテストデータベースは「データ損失」で復元され、破損しています。驚いたことに、ゴーストのクリーンアッププロセスは明らかにそのデータベースでスタックしていました。破損したデータベースをSMSSから削除すると、問題は自動的に解決しました(長時間かかり、DBが短時間ロックアップする可能性がありました)。