計算列のスカラーUDFが並列処理を禁止しないようにする方法はありますか?


29

SQL ServerのScalar UDF危険性について多くのことが書かれています。カジュアル検索では、大量の結果が返されます。

ただし、スカラーUDFが唯一のオプションである場所がいくつかあります。

例として:XMLを扱う場合:XQueryは計算列定義として使用できません。Microsoftによって文書化された1つのオプションは、Scalar UDFを使用してXQueryをScalar UDFにカプセル化し、それを計算列で使用することです。

これにはさまざまな効果があり、いくつかの回避策があります。

  • テーブルが照会されたときに行ごとに実行します
  • テーブルに対するすべてのクエリを強制的にシリアルに実行します

関数をスキーマバインドし、計算列を永続化するか、インデックスを作成することで、行ごとの実行を回避できます。これらのメソッドはいずれも、スカラーUDFが参照されていない場合でも、テーブルにヒットするクエリの強制シリアル化を防ぐことはできません。

それを行う既知の方法はありますか?

回答:


31

はい

  • SQL Server 2014以降を実行している。そして
  • トレースフラグ176をアクティブにしてクエリを実行できます。そして
  • 計算列は PERSISTED

具体的には、少なくとも次のバージョンが必要です

  • SQL Server 2016 SP1用の累積的な更新2
  • SQL Server 2016 RTMの累積的な更新4
  • SQL Server 2014 SP2用の累積的な更新6

しかし、バグを回避(のためのREFに2014を、そしてために2016年と2017年)の代わりに、それらの修正で導入され、適用されます。

トレースフラグは–T、を使用するグローバルスコープとセッションスコープの両方でDBCC TRACEON、およびクエリごとOPTION (QUERYTRACEON)またはプランガイドで、スタートアップオプションとして有効です。

トレースフラグ176は、永続的な計算列の展開を防ぎます。

クエリのコンパイル時に実行される初期メタデータのロードは、直接参照される列だけでなく、すべての列を取り込みます。これにより、すべての計算列の定義を照合に使用できるようになります。これは一般に良いことです。

不幸な副作用として、ロードされた(計算された)列の1つがスカラーのユーザー定義関数を使用する場合、計算列が実際に使用されていなくても、その存在によりクエリ全体の並列処理無効になります

トレースフラグ176は、列が永続化されている場合、定義をロードしないことでこれを支援します(展開がスキップされるため)。この方法では、スカラーのユーザー定義関数はコンパイルクエリツリーに存在しないため、並列処理は無効になりません。

トレースフラグ176の主な欠点(文書化されているだけではないこと)は、永続化された計算列と一致するクエリ式も防ぐことです:クエリに永続化された計算列と一致する式が含まれている場合、トレースフラグ176は式が置換されることを防ぎます計算列への参照。

詳細については、SQLPerformance.comの記事「適切に永続化された計算列」を参照してください。

質問では計算列とスカラー関数を使用して値をプロモートする代わりにXMLに言及しているため、「選択的XMLインデックス:悪くない」で書いたように、選択的XMLインデックスの使用も検討できます。


10

@Paulの優れたYes#1に加えて、実際にはYes#2があります。

  • SQL Server 2005にまでさかのぼりますが、
  • トレースフラグを設定する必要はありません。
  • 計算列がである必要ありません。PERSISTED
  • (トレースフラグ176を必要としないため)、クエリ式と永続化された計算列との一致を妨げませ

唯一の欠点は(私が知る限り)です:

  • Azure SQL Databaseでは動作しません(少なくともまだ動作していませんが、Linux上のSQL Serverと同様にAmazon RDS SQL Serverでも動作します)。
  • 多くのDBAの快適ゾーンの少し外側にあります

このオプションは次のとおりです。SQLCLR

そのとおり。SQLCLR Scalar UDFのクールな側面の1つはデータアクセスを行わない場合(ユーザーでもシステムでもない場合)、並列処理を禁止しないことです。そして、それは単なる理論やマーケティングではありません。完全に詳細な説明を行う時間はありませんが(現時点では)、これをテストして証明しました。

私は次のブログ投稿から初期設定を使用しました(うまくいけば、OPはこれを信頼できないソースとは見なしません🙃):

悪い考えのジーンズ:複数のインデックスヒント

そして、次のテストを実行しました。

  1. 初期クエリをそのまま実行しました─⇾並列処理(予想どおり)
  2. ([c2] * [c3])─⇾並列性(予想どおり)として定義された非永続計算列を追加しました
  3. その計算列を削除しSCHEMABINDINGRETURN (@First * @Second);─⇾NO Parallelism(予想どおり)として定義されたT-SQL Scalar UDF(で作成)を参照する非永続計算列を追加しました
  4. T-SQL UDF計算列を削除し、─⇾Parallelism (woo hoo !!)として定義されたSQLCLR Scalar UDF(両方IsDeterministic = trueで試行= false)を参照する非永続計算列を追加しましたreturn SqlInt32.Multiply(First, Second);

そのため、SQLCLRはすべての人に機能するわけではありませんが、適切な人/状況/環境には確かに利点があります。そして、この特定の質問(XQueryの使用に関して与えられた例)に関連しているので、そのための特定の作業になります(そして、具体的に何が行われているかによっては、少し速くなるかもしれません😎)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.