web-dev-qa-db-ja.com

クラスタ化された列ストアインデックスのパーティション列の最大値を取得する

  • SQL 2014 Enterprise
  • 約8億行のデータウェアハウステーブルがあります(テーブルの合計サイズは約25 GB)
  • このテーブルは、import_date列で分割されています(毎日)
  • クラスター化された列ストアインデックスがあります
  • 単純なSELECT MAX(t.import_date) FROM stat.t_auftragsstatistik tを実行すると、最大1億5000万行/ 33156ページを超えるクラスター化された列ストアインデックススキャンが実行されます。
  • 実行プランは https://www.brentozar.com/pastetheplan/?id=ryuskalug にあります。

一方、SELECT COUNT(*) FROM stat.t_auftragsstatistik AS ta WHERE ta.import_date = '20170201'(最新の日付)の場合、最大375k行が返され、この情報を収集するために6ページを読み取るだけで済みます。

質問:

  • max()が非常に遅く(〜7秒)、大量のデータを読み取るのはなぜですか(import_dateにクラスター化されていないインデックスがあると、単純なインデックススキャンが逆の順序で実行され、最初の一致後に停止します(-> 3回の読み取り))
  • なぜパーティション分割を無視するのですか(たとえば、毎週パーティション分割する場合でも、少なくとも1行の最新のパーティションをスキャンするだけで済みます)
1
Thomas Franz

最初に2番目の質問に対処すると、SQL Serverがその最適化にアクセスできないか、希望どおりに常に適用できるとは限らないようです。私は900万行のパーティション化されたヒープを毎年作成し、あなたと同じクエリを実行しました。 SQL Serverがパーティション関数を逆方向にループし、パーティション内にデータが見つかったときに停止したとしたら、それは素晴らしいことです。ただし、クエリオプティマイザは代わりに全表スキャンを実行しました。パーティション化された列にインデックスを配置する方がはるかに一般的だと思うので、基になるインデックスではなく、パーティション化スキームに高速のSELECT MAX(PARTITIONED_COLUMN)クエリを割り当てるのが自然です。それが助けになるなら、私は自分のコードを投稿することができます。

最初の質問に対処するために、7秒は8億行を処理するのに本当に遅いですか?クエリは並行して実行されるため、バッチモード処理を取得する必要があります。ただし、SQL Server 2014を使用しているため、集約プッシュダウンは発生しません。 Sunilには、同様の例で機能するブログ投稿 here があります。

次の図は、1,000万行を処理し、SALESテーブルから販売された数量の単一の集計合計を計算する集計クエリを示しています。

SELECT SUM (Quantity) FROM SALES

SQL Server 2014は、これらの1,000万行をバッチ(900行など)でスキャンし、これらのバッチを集計オペレーターに送信して集計を計算します。次の図は、SCANノードからAggregateノードに移動する1,000万行を示しています。

SQL Server 2016では、集計演算子自体がSCANノードにプッシュされ(つまり、データのソースに近い)、圧縮された行グループに対して集計が計算されます。次の図は、0行がSCANノードからAGGREGATEノードに移動したことを示しています。これは、集計がSCANノードで計算されたためです。

COUNT(*)クエリの場合、単一のパーティションで明示的にフィルタリングしています。 SQL Serverは、パーティションプルーニングを使用して、関連する行グループのみを取得することを期待しています。全体として、MAX()クエリはすべてのパーティションにヒットするため、クエリよりも高速で必要なリソースが少なくて済みます。

MAX()クエリについて質問されたのは主に好奇心からだったと思います。そのクエリを高速化する最も簡単な方法は、SQL Server 2016にアップグレードすることです。より迅速な方法として、行グループを調べて、適切なサイズであることを確認できます。行グループが少ない場合は、クエリがいくらか速くなると思います。または、テーブルのパーティション分割を利用する方法で最大値を見つける関数を作成することもできます。

2
Joe Obbish