4

こんにちは、各クエリが 35 以上のテーブルからデータを取得しているいくつかのレポートのクエリがいくつかあります。各テーブルには、ほぼ 100K のレコードがあります。たとえば、すべてのクエリは Union ALL です。

;With CTE
AS
(
Select col1, col2, col3 FROM Table1 WHERE Some_Condition
UNION ALL 
Select col1, col2, col3 FROM Table2 WHERE Some_Condition
UNION ALL 
Select col1, col2, col3 FROM Table3 WHERE Some_Condition
UNION ALL 
Select col1, col2, col3 FROM Table4 WHERE Some_Condition
.
.
. And so on 
)
SELECT col1, col2, col3 FROM CTE
ORDER BY col3 DESC

これまでのところ、Dev Server でこのクエリをテストしただけで、結果を得るのに時間がかかることがわかります。これらの 35 以上のテーブルはすべて互いに関連していません。これが、結果セット内のすべての必要なデータを取得するために考えられる唯一の方法です。

  1. この種のクエリを実行するより良い方法はありますか??

  2. これがこの種のクエリを実行する唯一の方法である場合、可能であれば変更を加えて、このクエリのパフォーマンスを向上させるにはどうすればよいですか??

私の意見
このレポートにいくつかの汚い読みがあってもかまいません。クエリヒント with nolockを使用する か、Transaction Isolation Levelに設定することを考えていましたREAD UNCOMMITED

これは役に立ちますか???

Edit
Every Tableには5〜10個のビット列と各ビット列に対応する日付列があり、各SELECTステートメントの条件は次のようなものです

WHERE BitColumn = 1 AND DateColumn IS NULL 

同僚による提案

フィルター処理されたインデックス

CREATE NONCLUSTERED INDEX IX_Table_Column
ON TableName(BitColumn)
WHERE BitColum = 1

列が含まれるフィルター処理されたインデックス

CREATE NONCLUSTERED INDEX fIX_IX_Table_Column
ON TableName(BitColumn)
INCLUDE (DateColumn)
WHERE DateColumn IS NULL

これが最善の方法ですか?または任意の提案をしてください???

4

4 に答える 4

2

より速くするためにできることはたくさんあります。これらのUNIONを実行する必要があると仮定すると、次の方法でクエリを高速化できます。

  1. たとえば、結果のキャッシュ
    • ステートメント全体からインデックス付きビューを作成できますか? それとも、さまざまな WHERE 条件がたくさんあるので、インデックス付きビューがたくさんあるのでしょうか? ただし、これにより、これらのテーブルの変更 (INSERT など) が遅くなることに注意してください。
    • 別の方法でキャッシュできますか?たぶん中間層?
    • 事前に再計算できますか?
  2. カバリングインデックスを作成します。先頭の列は WHERE からの列であり、クエリからの他のすべての列は含まれる列です。
    • カバリング インデックスもフィルター処理できますが、クエリの WHERE に変数/パラメーターがあり、フィルター処理されたインデックスでカバーされない値を持つ可能性がある場合 (つまり、行が対象)
  3. ORDER BY はソートを引き起こします
    • キャッシュできる場合は問題ありません-並べ替えは必要ありません(並べ替えられてキャッシュされます)
    • それ以外の場合、並べ替えは CPU バウンド (およびメモリ内にない場合は I/O バウンド) です。高速化するために、高速照合を使用しますか? 最も遅い照合と最も速い照合のパフォーマンスの差は 3 倍にもなります。たとえば、SQL_EBCDIC280_CP1_CS_AS、SQL_Latin1_General_CP1251_CS_AS、SQL_Latin1_General_CP1_CI_AS は、最も高速な照合順序の 1 つです。ただ、必要な照合特性が分からないとおすすめは難しいです。
  4. 通信網
    • SELECT を実行する接続の「ネットワーク パケット サイズ」は、可能な最大値にする必要があります。結果セット (行数) が大きくなる場合は 32,767 バイトです。これは、接続文字列で .NET と SqlConnection を使用する場合など、クライアント側で設定できます。これにより、SQL Server からデータを送信する際の CPU オーバーヘッドが最小限に抑えられ、クライアントとサーバーの両方でパフォーマンスが向上します。ネットワークがボトルネックだった場合、これによりパフォーマンスが数十パーセント向上する可能性があります
    • クライアントが SQL Server 上にある場合は、共有メモリ エンドポイントを使用します。それ以外の場合は、最高のパフォーマンスを得るために TCP/IP
  5. 一般的なこと
    • あなたが言ったように、分離レベル read uncommitted を使用するとパフォーマンスが向上します

...

おそらく、クエリの書き換えなどを超えて変更を行うことはできませんが、念のため、現在十分でない場合に備えてメモリを追加するか、メモリ機能でSQL Server 2014を使用します:-)、...確かに役立ちます.

調整できることは多すぎますが、質問があまり具体的でない場合、重要なものを指摘するのは困難です。

これが少し役立つことを願っています

于 2013-10-27T20:34:50.440 に答える
1

実行の統計やサンプル実行時間を提供していないため、何が遅いのか、本当に遅いのかを推測することはできません。結果セットにはどのくらいのデータがありますか? 結果として時間がかかるだけなので、100K行を取得するだけかもしれません。10000 行の結果セットに 5 分かかる場合は、確かに何かを確認できます。したがって、サンプルクエリ、結果の行数、および異なる場所条件でのいくつかの実行にかかった時間がある場合は、それを投稿してください。結果を比較するのに役立ちます。

ところで、CTEを使用しないでください。通常の内部および外部クエリ選択を使用してください。Temp DB が正しく構成されていることを確認してください。LDF および MDF は、デフォルトで 10% 増加するように構成されていません。特定の試行錯誤により、真正な範囲クエリに対してログおよび一時 DB がどれだけ増加するかがわかるようになり、それに基づいて、一時 DB の MDF および LDF の初期サイズおよび増分サイズを設定する必要があります。Covered フィルター インデックスの場合、日付が選択リストに含まれていない限り、含める列は列 Date ではなく、col1、col2、および co3 にする必要があります。

元の 35 個のテーブルのデータが更新される頻度は? 最大で 1 日 1 回の場合、またはすべてがほぼ同時に更新される場合は、Indexed-Views が解決策になる可能性があります。ただし、元のテーブルが 1 日に複数回更新されるか、いつでも更新され、同じ行にある場所がない場合は、Indexed-View について考えないでください。

最後の手段としてディスク容量が問題にならない場合は、35 個のテーブルごとにトリガーを使用してパフォーマンスをテストしてください。この選択クエリから期待されるように、最終結果を保持する新しいテーブルを作成します。トリガー内の条件をチェックする各35テーブルに挿入/更新/削除トリガーを作成し、そうであれば、同じ挿入/更新/削除のみを新しいテーブルにコピーします。はい、どのデータがどのテーブルから来ているかを識別する新しいテーブルの列が必要になります。Date は Null-Able 列であるため、「ほとんどの場合、WHERE Date が NULL を探している」ため、その列の Index を十分に活用できません。新しいテーブルのみのクエリでは、DateがNULLの場合、その列を作成することさえ気にせず、BIT列と他のcol1、col2、col3などを作成するだけです...クエリの実際の例を示し、実際を説明する場合テーブル、

于 2013-10-25T03:22:37.080 に答える