すべてのSSRSレポート生成をオフロードするために、スタンバイ/読み取り専用のセカンダリSQLサーバーへのログ配布を設定しました。
これは、以下によって課される制限内で正常に機能します。
残念ながら、すべてのストアドプロシージャを初めて実行したときは、トランザクションログが復元された後、通常よりも完了するまでにかなり長い時間がかかります。その同じストアドプロシージャの後続のすべての実行は、予想される時間内に完了します。次に別のストアドプロシージャを実行すると、最初は低速で、後続のすべての実行は予想時間内に完了します。
参考までに、実行の違いは通常、最初の実行の〜01:00と比較して〜00:02です。
これは、サーバーの実行統計またはストアドプロシージャのパラメータースニッフィング/ストアド実行プランのいずれかに関係があると思います。
この問題を回避する方法はありますか?または、これはトランザクションログの復元に固有のものですか?
ストアドプロシージャを初めて実行しただけの場合は、復元時にストアドプロシージャを実行することで簡単に回避できますが、すべてのストアドプロシージャを初めて実行したときに影響があるようです。
タッチのテストに使用しているストアドプロシージャを11個のテーブルでcount( * )
を実行してみました。最初の実行には00:32、後続のcount(*)には00:00がかかりました。残念ながら、これはストアドプロシージャの最初の実行に影響を与えませんでした。
ストアドプロシージャの実行前でも実行後でも、プライマリサーバーまたはセカンダリサーバーでis_temporary
統計の結果が表示されません。
現在SQL Server 2012を使用しています
クエリ実行計画:
一見するとクエリ実行プランは大きく異なりますが、実行プランを保存して生成された.sqlplanファイルを開くと、まったく同じです。違いは、私が使用しているSSMSのバージョンが異なるためで、2014年はプライマリサーバーで、2018年はセカンダリサーバーで発生しているようです。セカンダリで実行プランを表示すると、すべてのノードの%と時間コスト###の###(##%)の下に表示されます。これらの数値も実際の実行プランも、以降の実行で変化しません。
クライアントの統計情報も含めましたが、ほぼまったく同じです。唯一の違いは、プライマリサーバーがサーバー応答の待機時間1.4秒で実行され、セカンダリサーバーが81.3秒かかることです。
予想通り、最初の実行から多数のPAGEIOLATCH_SHロックが表示されます。
diff after first exec vs diff after second exec
waiting_tasks_count 10903 918
wait_time_ms 411129 12768
この状況の奇妙なことの1つは、セットアップのラウンドロビンの複数インスタンスの一部を除いて、定期的なトランザクションログによって供給され、発生しないスタンバイ/読み取り専用データベースから読み取りを行う本番SSRSサーバーが既にあることです。これらは、ストアドプロシージャの最初の実行時にスローダウンします。ただし、トランザクションログが復元されるたびにユーザーが開始されます。これは、上記の設定で解決されるはずの問題です。
ここではいくつかの可能性のあることが起こりますが、これは完全ではないリストです:
PAGEIOLATCH*
_ 待機が表示されます。これを軽減するためにできることがいくつかあります
SELECT COUNT(*) FROM dbo.YourTable
を使用して重要なテーブルからメモリにすべてのデータを読み込むことにより)、実行計画の「高速」と「低速」の例を提供すると、発生していることを正確に追跡するのに役立ちます。
SQL Server 2012以降を使用している場合は、同期統計の更新が原因で遅延が発生している可能性があります。ログ配布のセカンダリは読み取り専用であるため、これらの「読み取り可能なセカンダリ統計」はTempDBで作成されます。詳細については、こちらをご覧ください(記事はAGについてですが、このシナリオでも同じことが当てはまります)。
AlwaysOn:最新の統計を読み取り可能なセカンダリ、読み取り専用データベースおよびデータベーススナップショットで利用可能にする
これがスローダウンの原因となっている問題である場合、1つの解決策は、それらの統計を見つけて、それを本番データベースに作成し、復元後に最新で利用できるようにすることです。このクエリで一時的な統計を探すことができます:
_SELECT * FROM sys.stats WHERE is_temporary = 1;
_
指定した待機統計と、プランが同じであるという事実に基づいて、ログリストアによってバッファプールがクリアされるため、これはかなりの結論になります。
通常の実行では、12,768ミリ秒(ほぼ13秒)のIO待機が発生します。
最初の実行では、411,129 ms(ほぼ7分)IO待機)を取得します。
実際のプロシージャとSELECT COUNT(*)
クエリでは異なるインデックスが使用されているため、試したCOUNT(*)
アプローチは役に立たなかった可能性があります。ここにはいくつかのオプションがあります。
SELECT COUNT(*) FROM dbo.YourTable WITH (INDEX (IX_Index_Being_Used_By_Proc))
)