3

SQL Serverには、CLR統合ベースのテーブル値関数GetArchiveImagesがあります。私はそれを次のように呼んでいます:

SELECT ...
FROM Items
CROSS APPLY GetArchiveImages(Items.ID) AS archiveimages
WHERE ...

問題は、関数への個々の呼び出しごとにオーバーヘッドがあることです。

テーブル全体と一度に結合できる場合、オーバーヘッドはごくわずかですが、行ごとに1回呼び出されるため、そのオーバーヘッドは行数に比例します。

ストアドプロシージャによって返されるテーブルは(私が知る限り)何とも結合できないため、ストアドプロシージャは使用しません。

行ごとではなく、ストアドプロシージャまたは関数の結果をまとめてテーブルに結合する効率的な方法はありますか?

4

2 に答える 2

3

GetArchiveImagesの結果はItems.IDに依存するため、SQL Serverは各アイテムの関数を呼び出す必要があります。そうしないと、正しい結果が得られません。

SQL Serverが「分割」できる唯一の関数は、T-SQLインラインテーブル値関数です。したがって、CLRをITVFとして書き直すことができれば、パフォーマンスが向上します。

しかし、私の経験では、CLR関数を呼び出すことのやり過ぎはそれほど大きくありません。クエリのどこかで問題が発生している可能性がはるかに高くなります。たとえば、SQL Serverは、その関数によって返される行数を認識せず、(呼び出しごとに)1行になると想定します。これは、最適化プロセス中に他の場所で誤った情報に基づいた決定につながる可能性があります。


アップデート:

SQL Serverでは、静的な非定数データをCLRクラス内に保持することはできません。システムをだます方法はあります。たとえば、静的な最終コレクションオブジェクトを作成する(静的コレクションからアイテムを追加および削除できます)などですが、安定性の理由から、これには反対することをお勧めします。

あなたの場合、ある種の(データベースまたはファイルシステム)トリガーで自動的に、またはスケジュールに従って更新されるキャッシュテーブルを作成することは理にかなっているかもしれません。関数を呼び出す代わりに、そのテーブルに参加することができます。

于 2013-01-15T15:24:31.017 に答える
2

GetArchiveImages()関数を複数のクエリで使用する必要がない場合、または少なくとも同様のクエリの外部で使用する必要がない場合は、この外部と内部の側面を切り替えることができます。SQLCLRTVFでメインをSELECT fields FROM [Items] WHERE ...実行します。そしてそれをストリーミングTVFにします。

必要な基本構造は次のとおりです。

  1. タイプSqlDataRecordの変数を、[Items]から返すすべてのフィールドと、現在のGetArchiveImages()関数によって返される他のフィールドになるように定義します。

  2. 「ファイルシステム内のいくつかのファイル」を読んでください(@Sebastian Meineの回答の最初のコメントから引用)

  3. "Trusted_Connection = true; Enlist = false;"ConnectionStringとしてを使用してSqlConnectionを開きます。

  4. メインを実行しSELECT fields FROM [Items] {optional WHERE}ます。この時点で一部の行を絞り込むことができる場合は、に入力しWHEREます。関数に値を渡して、WHERE句に渡すこともできます。

  5. :をループしSqlDataRecordます

    1. この行のSqlDataRecord変数を入力します
    2. GetArchiveImages()現在の関数が基づいている関連アイテムを取得します[Items].[ItemID]
    3. 電話yield return;
  6. 閉じますSqlConnection

  7. 、、、およびSqlDataReaderを破棄します。SqlCommandSqlConnection

  8. 手順2で開いたファイルをすべて閉じます(プロセスの早い段階で閉じることができない場合)。

于 2015-01-31T20:01:08.797 に答える