クエリのリモート実行オプションを比較する

SQL Server には、クエリをリモートで実行する方法が 3 つあります。

  • OPENQUERY
  • OPENROWSET
  • EXECUTE AT

この記事では、これら 3 つの方法について説明します。

OPENQUERY

OPENQUERY (Transact-SQL)

指定されたパススルー クエリを、指定されたリンク サーバーで実行します。 このサーバーは OLE DB データ ソースです。 クエリでは、FROMOPENQUERY をテーブル名であるかのように使います。 また、OPENQUERYINSERTUPDATE、または DELETE ステートメントのターゲット テーブルとして参照することもできます。 これは OLE DB プロバイダーの機能により制限されます。 クエリからは複数の結果セットが返される場合がありますが、OPENQUERY からは最初の 1 つだけが返されます。

OPENQUERY には、事前に追加され構成済みであるリンク サーバーと、リモート サーバーへの要求テキストが必要です。 OPENQUERY では、オブジェクトにアクセスするために 4 部構成の名前の規則は必要ありません。

OPENROWSET

OPENROWSET (Transact-SQL)

OLE DB データ ソースからリモート データへのアクセスに必要な、すべての接続情報をインクルードします。 このメソッドは、リンク サーバー内のテーブルにアクセスする代わりに、OLE DB を使用してリモート データに接続しアクセスするアドホック メソッドです。 OLE DB データ ソースへの参照をより頻繁に行う場合は、リンク サーバーPolyBase、または SQL Server Integration Services (SSIS) やカスタム アプリケーションなどのツールを介した 2 つのデータ ソース間の直接接続を使うことを検討してください。

クエリでは、クエリの FROM 句で OPENROWSET を使います。 また、INSERTUPDATE、または DELETE ステートメントのターゲット テーブルとして OPENROWSET を使うこともできます。これは OLE DB プロバイダーの機能により制限されます。 クエリでは複数の結果セットが返される場合がありますが、OPENROWSET では最初の 1 つだけが返されます。

OPENROWSET では、組み込みの BULK プロバイダーによる一括操作もサポートされ、ファイルのデータを行セットとして読み取り、返すことができます。

追加情報のために、OPENROWSET では明示的に書き込まれた接続文字列を使います。

EXECUTE AT

EXECUTE (Transact-SQL)

リンク サーバーに対して動的 SQL を実行できます。 EXECUTE 呼び出しのパラメーターの 1 つは AT です。これは、OPENQUERYOPENROWSET の制限をバイパスするように設計されています。 EXECUTE (``<query>``) AT [<linked server>] は、リモート サーバーから任意の数の結果セットを返すことができる動的 SQL です。

動的 SQL に関するガイダンス

アプリケーションでは動的 SQL コマンドを使わないようにし、動的 SQL コマンドにアクセスできるユーザーに対してアクセス許可を制限してください。 EXECUTE を使って実行するクエリを構築することは、SQL インジェクション攻撃を介した Web サイトやアプリケーションに対する脆弱性につながるおそれがあります。 詳細については、「 SQL Injection」を参照してください。

パフォーマンスが問題になる場合は、リモート クエリをテストします。

  • できるだけ多くのロジックがリモート サーバーで実行されるようにします
  • クエリをサポートするために、リモート サーバーのインデックス テーブルのインデックスを適切に確認します
  • コードベースでリモート クエリを使うと、データベース コードのバージョン コントロール、および開発環境とテスト環境のメンテナンスが複雑になる点に注意してください

A. OPENQUERY を使った SELECT パススルー クエリを実行する

次の例では、OPENQUERY と共に SELECT パススルー クエリを使って行を選択します。

SELECT * 
    FROM OPENQUERY ([linkedserver], 
        'SELECT * FROM AdventureWorksLT.SalesLT.Customer');  

B. OPENROWSET を使った SELECT パススルー クエリを実行する

次の例では、OPENROWSET と共に SELECT パススルー クエリを使って行を選択します

SELECT a.*
FROM OPENROWSET('MSOLEDBSQL', [linkedserver],
     'SELECT * FROM AdventureWorksLT.SalesLT.Customer') AS a;

SQL Server Native Client (SNAC と略されることがよくあります) は、SQL Server 2022 (16.x) と SQL Server Management Studio 19 (SSMS) から削除されました。 SQL Server Native Client OLE DB プロバイダー (SQLNCLI または SQLNCLI11) とレガシ Microsoft OLE DB Provider for SQL Server (SQLOLEDB) はどちらも、新しい開発には推奨されません。 今後は、新しい Microsoft OLE DB Driver (MSOLEDBSQL) for SQL Server に切り替えてください。

C. EXECUTE AT を使った SELECT パススルー クエリを実行する

次の例では、EXECUTE ... AT と共に SELECT パススルー クエリを使って行を選択します

EXECUTE ('SELECT * FROM AdventureWorksLT.SalesLT.Customer') AT [linkedserver]

D. 複数の SELECT ステートメントを実行する

次の例では、SELECT パススルー クエリを使って、複数の結果セットを取得します

EXECUTE ('SELECT TOP 10 * FROM AdventureWorksLT.SalesLT.Customer;
    SELECT TOP 10 * FROM AdventureWorksLT.SalesLT.CustomerAddress;') AT [linkedserver];

E. SELECT を実行し、2 つの引数を渡す

次の例では、2 つの引数を指定するパススルー SELECT を使います

EXECUTE ('SELECT TOP 10 * FROM AdventureWorksLT.SalesLT.Customer 
WHERE CustomerID = ? AND LastName = ?', 10, 'Garza') AT [linkedserver];

F. SELECT を実行し、変数を使って 2 つの引数を渡す

次の例では、変数を使って 2 つの引数を指定するパススルー SELECT を使います

DECLARE @CustomerID AS INT
DECLARE @LastName AS VARCHAR(100)
SET @CustomerID = 10
SET @LastName = 'Garza'
EXECUTE ('SELECT TOP 10 * FROM AdventureWorksLT.SalesLT.Customer 
WHERE CustomerID = ? AND LastName = ?', @CustomerID, @LastName) AT [linkedserver];

G. リンク サーバーを使って EXECUTE で DDL ステートメントを実行する

次の例では、リンク サーバーで DDL ステートメントを使います

EXECUTE (
'USE TempDB
IF OBJECT_ID(''dbo.Table1'') IS NOT NULL
DROP TABLE dbo.Table1
CREATE TABLE dbo.Table1
(
    Column1 INT
)' ) AT [linkedserver];

テストが完了したら、作成したオブジェクトをクリーンアップします

EXECUTE (
'USE TempDB
IF OBJECT_ID(''dbo.Table1'') IS NOT NULL
DROP TABLE dbo.Table1'
) AT [linkedserver];
EXECUTE sp_dropserver 'linkedserver'

その他の例

INSERT...SELECT * FROM OPENROWSET(BULK...) のその他の使用例については、次のトピックをご覧ください。

参照