2013-03-04 22 views
13

私は次のクエリは、リンクサーバーからの結果セットをプルダウンすることを承知している:SELECTとINSERTのOPENQUERYはどのように異なっていますか?

SELECT * FROM openquery(DEVMYSQL, 
    'SELECT event_id, people_id, role_id, rank, last_updated FROM event_cast') 

はしかし、これは挿入に来る同じケースですか?結果セットをプルダウンするか、列情報を取得するだけですか?

INSERT INTO openquery(DEVMYSQL, 
    'SELECT event_id, people_id, role_id, rank, last_updated FROM event_cast') 

前者の場合、これは非常に非効率的です。返される結果セットを制限する必要がありますか?これは私のINSERTに影響しますか?

これはSELECTINSERTになると、基本的にはOPENQUERYがどのように動作するかという質問です。

何か助けていただきありがとうございます。

答えて

10

、あなたのINSERTで達成しようとするのかわかりません。

正しい構文(リモートサーバ上で挿入したい場合)

INSERT into openquery(MyServer, 'dbo.event_cast') values ('','') 

あるべき選択は唯一の選択クエリはあなたに追加の情報を与えることなく(無駄に)返し、これまで何を検索し、あなたの挿入を遅らせます。また、あなたが挿入のために、より正確には、次の構文を使用することができOPENQUERYを持つ:ローカルサーバーに挿入しようとしている場合

INSERT into myserver.mydatabase.dbo.event_Cast values('','') 

しかし、構文を選択することにより、取得した値は次のようになります。

INSERT into dbo.my_localtable SELECT * FROM openquery(DEVMYSQL, 'SELECT event_id, people_id, role_id, rank, last_updated FROM event_cast') 

はい、文は列情報だけでなく値も挿入します。あなただけがINSERTを実行するためにOPENQUERYを使用する場合

+2

FYI:2番目の例の4つの部分の名前付け構文は、リンクサーバータイプが分散トランザクションに登録されている場合にのみ機能します。 (ほとんどの場合、ちょっとしたことです) –

+0

最初のクエリでは、selectを使用して列を指定せずに挿入する列をどのように決定していますか? – Abs

+0

完全な挿入は、アイデンティティデータまたはデフォルトデータ(ほとんどの場合、デフォルトデータも書き込む)で列を残してしまいます。通常、レコードセット全体をデータのまとまりとして書き込むために、挿入するレコードセット全体を与える方が高速です。 openqueryは、列が挿入順であると想定しています(通常の挿入がそうであるように)。 True:非連続列を具体化する必要がある場合は、選択肢を使用する必要がありますが、パフォーマンスは低下します – Zelloss

4

SELECTがレコードを返す場合、INSERTは影響を受けるレコードの数を除いて結果セットを返しません。これは、SET NOCOUNT ONを使用することで抑止できます。しかし、抑制が可視性を参照するか、行数が実際に来るかどうかはわかりません。

INSERT INTO OPENQUERY(MYSERVER, 'SELECT [Drive_Letter] ,[MBFree],[Server] FROM [Blah].[dbo].[SQL_Drives]') 
    SELECT 'X', 2, 'MyServer' 

(1 row(s) affected) 

INSERTから返されるレコードは、OUTPUT句を使用する唯一の方法です。クライアント・マシンは、OUTPUT INSERTED行にアクセスできないため、戻されません。あなたは次のことを実行しようとすると、エラーが表示されます:

INSERT INTO OPENQUERY(MYSERVER, 'SELECT [Drive_Letter] ,[MBFree],[Server] FROM [BLAH].[dbo].[SQL_Drives]') 
OUTPUT INSERTED.* 
SELECT 'X', 2, 'MyServer' 

Msg 405, Level 16, State 1, Line 1 
A remote table cannot be used as a DML target in a statement which includes an OUTPUT clause or a nested DML statement. 


-- EDIT RESULTS OF PROFILER ---------------------------  


-- Statements that occured on server called through OPENQUERY 
    exec sp_cursoropen @p1 output,N'SELECT [Drive_Letter] ,[MBFree],[Server] FROM [MyServer].[dbo].[SQL_Drives]',@p3 output,@p4 output,@p5 output 
    select @p1, @p3, @p4, @p5 

    exec sp_cursor 180150009,4,0,N'[MyServer].[dbo].[SQL_Drives]',@Drive_Letter='X',@MBFree=2,@Server='MyServer' 


--Statements that occured on client 
    INSERT INTO OPENQUERY(MyServer, 'SELECT [Drive_Letter] ,[MBFree],[Server] FROM [MyServer].[dbo].[SQL_Drives]') 
    SELECT 'X', 2, 'MyServer' 
+0

私が 'INSERT'を参照するとき、私は実際に' OPENQUERY'内の 'SELECT'について話しています。このクエリはリンクされたサーバ上で実行され、 'INSERT'がローカルサーバ上で実行されます。しかし、SQL Serverはそれが 'INSERT'であることを認識し、リンクされたサーバーから結果セットを返さないでしょうか? – Abs

+0

私はちょうど同じステートメントを実行し、それぞれの端にプロファイラを見ました。結果は上記のとおりです。これは、SELECTがOPENQUERYによって呼び出されているサーバー上でのみ発生し、SELECTが他のものよりも挿入のテンプレートとして機能すると考えています。 – PseudoToad

1

を十分でしょう

SELECT top 1 * into new_local_event_cast FROM openquery(DEVMYSQL, 'SELECT event_id, people_id, role_id, rank, last_updated FROM event_cast'); 
TRUNCATE TABLE new_local_event_cast; 

ローカルに単純なテーブルを複製する場合は

、それはSELECT最初に実行し、結果を捨てます。結果セットの列メタデータを使用して、INSERTコマンドの送信方法を決定します。そのため、の末尾には常にwhere 1=0を追加する必要があります。

SQL ServerからMySQLへの適切な構文は次のとおりです。

insert into openquery(MYSQLDEV, 'select * from insert_test where 1=0') values ('test'); 

はMySQL側で一般クエリログを有効にした場合、あなたは、これらのコマンドは、SQL Serverから表示されます:

SET NAMES utf8 
SET character_set_results = NULL 
SET SQL_AUTO_IS_NULL = 0 
set @@sql_select_limit=1 
select * from insert_test where 1=0 
select * from insert_test where 1=0 
INSERT INTO `database`.`insert_test`(`column`) VALUES ('test') 

選択が2回実行されていることがわかります。 where 1=0がなければ、すべての行はMySQLサーバによって返されます。

関連する問題