この質問はJakeManskeによって#sqlhelpに投稿され、ErikDarlingによって私の注意を引きました。
sys.partitions
でパフォーマンスの問題が発生したことを覚えていません。 。私の最初の考え(Joey D'Antoniによってエコーされた)は、data_compression
のフィルターでした。 列すべき 冗長スキャンを回避し、クエリの実行時間を約半分に短縮します。ただし、この述語はプッシュダウンされないため、少し解凍する必要があります。
sys.partitionsが遅いのはなぜですか?
sys.partitions
の定義を見ると 、それは基本的にジェイクが説明したものです– UNION ALL
THREE を使用して、すべての列ストアおよび行ストアパーティションの sys.sysrowsets
への明示的な参照 (ここに省略されたソース):
CREATE VIEW sys.partitions AS WITH partitions_columnstore(...cols...) AS ( SELECT ...cols..., cmprlevel AS data_compression ... FROM sys.sysrowsets rs OUTER APPLY OpenRowset(TABLE ALUCOUNT, rs.rowsetid, 0, 0, 0) ct -------- *** ^^^^^^^^^^^^^^ *** LEFT JOIN sys.syspalvalues cl ... WHERE ... sysconv(bit, rs.status & 0x00010000) = 1 -- Consider only columnstore base indexes ), partitions_rowstore(...cols...) AS ( SELECT ...cols..., cmprlevel AS data_compression ... FROM sys.sysrowsets rs -------- *** ^^^^^^^^^^^^^^ *** LEFT JOIN sys.syspalvalues cl ... WHERE ... sysconv(bit, rs.status & 0x00010000) = 0 -- Ignore columnstore base indexes and orphaned rows. ) SELECT ...cols... from partitions_rowstore p OUTER APPLY OpenRowset(TABLE ALUCOUNT, p.partition_id, 0, 0, p.object_id) ct union all SELECT ...cols... FROM partitions_columnstore as P1 LEFT JOIN (SELECT ...cols... FROM sys.sysrowsets rs OUTER APPLY OpenRowset(TABLE ALUCOUNT, rs.rowsetid, 0, 0, 0) ct ------- *** ^^^^^^^^^^^^^^ *** ) ...
このビューは、おそらく下位互換性の懸念のために、一緒に石畳になっているようです。特にsys.sysrowsets
のみを参照するように、より効率的に書き直すことができます。 およびTABLE ALUCOUNT
オブジェクトを一度。しかし、あなたや私が今それについてできることはあまりありません。
列cmprlevel
sys.sysrowsets
から取得 (列参照のエイリアスプレフィックスが役立ちます)。 OUTER APPLY
の前に、そこにある列に対する述語が論理的に発生することを期待します。 スキャンの1つを防ぐことができますが、それは起こりません。次の簡単なクエリを実行します:
SELECT * FROM sys.partitions AS p INNER JOIN sys.objects AS o ON p.object_id = o.object_id WHERE o.is_ms_shipped = 0;
データベースに列ストアインデックスがある場合、次のプランが生成されます(クリックして拡大):
列ストアインデックスが存在するsys.partitionsの計画
そして、ない場合は次の計画(クリックして拡大):
列ストアインデックスが存在しないsys.partitionsの計画
これらは同じ推定計画ですが、SentryOne Plan Explorerは、実行時に操作がスキップされたときに強調表示できます。これは後者の場合の3回目のスキャンで発生しますが、その実行時スキャン数をさらに減らす方法があるかどうかはわかりません。 2番目のスキャンは、クエリがゼロ行を返した場合でも発生します。
ジェイクの場合、彼はたくさんを持っています オブジェクトの数が多いため、このスキャンを2回実行しても、目立ち、苦痛を伴い、1回は多すぎます。そして正直なところ、TABLE ALUCOUNT
かどうかはわかりません 、内部の文書化されていないループバック呼び出しも、これらの大きなオブジェクトのいくつかを複数回スキャンする必要があります。
ソースを振り返って、計画の形を強制することができるビューに渡すことができる他の述語があるかどうか疑問に思いましたが、実際に影響を与える可能性のあるものはないと思います。
別のビューは機能しますか?
ただし、まったく別のビューを試すこともできます。両方のsys.sysrowsets
への参照を含む他のビューを探しました およびALUCOUNT
、リストに表示されるものは複数ありますが、有望なのは2つだけです:sys.internal_partitions
およびsys.system_internals_partitions
。
sys.internal_partitions
sys.internal_partitions
を試しました 最初:
SELECT * FROM sys.internal_partitions AS p INNER JOIN sys.objects AS o ON p.object_id = o.object_id WHERE o.is_ms_shipped = 0;
しかし、計画はそれほど良くはありませんでした(クリックして拡大):
sys.internal_partitionsの計画
sys.sysrowsets
に対するスキャンは2つだけです。 今回は、クエリが目的の行の生成に近づかないため、スキャンはとにかく無関係です。列ストア関連のオブジェクトの行のみが表示されます(ドキュメントに記載されています)。
sys.system_internals_partitions
sys.system_internals_partitions
を試してみましょう 。サポートされていないため(ここの警告を参照)、これについては少し警戒していますが、しばらくお待ちください:
SELECT * FROM sys.system_internals_partitions AS p INNER JOIN sys.objects AS o ON p.object_id = o.object_id WHERE o.is_ms_shipped = 0;
列ストアインデックスを使用するデータベースでは、sys.sysschobjs
に対するスキャンがあります。 、ただし現在は1つのみ sys.sysrowsets
に対してスキャンします (クリックして拡大):
列ストアインデックスが存在するsys.system_internals_partitionsの計画
列ストアインデックスを使用せずにデータベースで同じクエリを実行すると、計画はさらに単純になり、sys.sysschobjs
に対してシークが行われます。 (クリックして拡大):
列ストアインデックスが存在しない場合のsys.system_internals_partitionsの計画
ただし、これはかなりではありません 列ストアインデックスからのアーティファクトも含まれているため、私たちが求めているもの、または少なくともJakeが求めていたものではありません。これらのフィルターを追加すると、実際の出力は以前のはるかに高価なクエリと一致するようになります。
SELECT * FROM sys.system_internals_partitions AS p INNER JOIN sys.objects AS o ON p.object_id = o.object_id WHERE o.is_ms_shipped = 0 AND p.is_columnstore = 0 AND p.is_orphaned = 0;
ボーナスとして、sys.sysschobjs
に対するスキャン 列ストアオブジェクトを使用するデータベースでもシークになっています。私たちのほとんどはその違いに気付かないでしょうが、ジェイクのようなシナリオにいる場合は、(クリックして拡大):
追加のフィルターを使用した、sys.system_internals_partitionsのより簡単な計画
sys.system_internals_partitions
sys.partitions
とは異なる列のセットを公開します (完全に異なるものもあれば、新しい名前を持つものもあります)。したがって、ダウンストリームで出力を消費する場合は、それらに合わせて調整する必要があります。また、行ストア、メモリ最適化、列ストアのインデックス全体で必要なすべての情報が返されることを検証する必要があります。これらの厄介なヒープを忘れないでください。そして最後に、s
を除外する準備をします internals
何度も何度も。
結論
前述したように、このシステムビューは公式にはサポートされていないため、その機能はいつでも変更される可能性があります。また、Dedicated Administrator Connection(DAC)の下に移動したり、製品から完全に削除したりすることもできます。 sys.partitions
の場合は、このアプローチを自由に使用してください はうまく機能していませんが、バックアップ計画があることを確認してください。また、念のため、SQL Serverの将来のバージョンのテストを開始するとき、またはアップグレードした後に、回帰テストとして文書化されていることを確認してください。