views:

442

answers:

5

I need to execute three dynamic SQL statements synchronously on a linked server (SQL Server 2005) like this:

declare @statement nvarchar(max);

set @statement = 'exec ' + @server_name + '.' + @database_name + '.dbo.Foo;exec ' + @server_name + '.' + @database_name + '.dbo.Bar;exec ' + @server_name + '.' + @database_name + '.dbo.BigTime';

exec sp_executesql @statement;

To test this, I have a linked server setup that links to itself.

When executing this local (by removing the @server_name), using SQL Profiler I see that it executes just fine as one statement. However, when I execute this via the linked server (using the @server_name variable), I see in SQL Profiler that each statement gets executed separately, with sp_reset_connection getting executed after each one.

The trace looks something like this:

Audit Login ....
exec database.dbo.Foo
exec sp_reset_connection
Audit Logout
Audit Login ....
exec database.dbo.Bar
exec sp_reset_connection
Audit Logout
Audit Login ....
exec database.dbo.BigTime
exec sp_reset_connection
Audit Logout

This is causing me problems. Is there any why I can specify to SQL Server to not call sp_reset_connection between statements?

A: 

Can you not make a single SP on the linked server which calls the other 3 and then just call that one?

Why does the reset connection cause a problem? Does each SP use some special kind of connection persistent storage like a temp table or something?

Cade Roux
I can't modify anything on the linked server. And yes, resetting the connection is causing a problem.
Aaron Daniels
+1  A: 

You are executing three calls to three linked servers, the result is exactly what you should be expecting (even if the 3 linked servers are not distinct). To achieve what describe, execute the calls as you describe: execute three procedures on one linked server:

linkedserver.master.dbo.sp_ExecuteSQL N'
  exec dbname.dbo.Foo; 
  exec dbname.dbo.Bar; 
  exec dbname.dbo.BigTime;';

All you have to do is wrap this around in a dynamic built SQL:

declare @remoteStatement nvarchar(max), @localStatement nvarchar(max);
set @remoteStatement = N'exec ' + @database_name + N'.dbo.Foo; 
    exec ' + @database_name + N'.dbo.Bar; 
    exec '+ @database_name + N'.dbo.BigTime';
set @localStatement = @server_name + N'.master.dbo.sp_executesql @remoteStatement;';

exec sp_executesql @localStatement, N'@remoteStatement nvarchar(max)', @remoteStatement;
Remus Rusanu
Remus, I posted something quite similar. Your declare line, however, will bomb out.
Aaron Bertrand
Thanks Aaron, I fixed it. Serves me right for posting without even doing a syntax check...
Remus Rusanu
A: 

This may help:

BEGIN DISTRIBUTED TRANSACTION
 your stuff here
COMMIT TRANSACTION

For this you will need distributed transaction coordinator running.

Damir Sudarevic
This didn't work. I get: "The server failed to resume the transaction. Desc:3500000006." returned. This was a good thought though.
Aaron Daniels
Is the MS DTC running?
Damir Sudarevic
+2  A: 
DECLARE @sql1 NVARCHAR(MAX), @sql2 NVARCHAR(MAX);

SET @sql1 = 'EXEC ' + @database_name + '.dbo.Foo;'
          + 'EXEC ' + @database_name + '.dbo.Bar;'
          + 'EXEC ' + @database_name + '.dbo.BigTime;';

SET @sql2 = 'EXEC ' + @server_name + '.master.dbo.sp_executeSQL ''' + @sql1 + ''';';

EXEC sp_executeSQL @sql2;
Aaron Bertrand
It's master.sys.sp_executesql, btw. I really liked this idea, but to my astonishment, it's behaving very similar. Using SQL Profiler, I see that it fires the first one, then the second, then fires off sp_executesql with all three as the statement parameter!?!
Aaron Daniels
? This seems to work fine for me: EXEC master.dbo.sp_executeSQL N'print ''1'';'; ... as for the multiple calls, which server are you running profiler against, the one firing the commands or the one receiving them (@server_name)?
Aaron Bertrand
For testing, I was doing everything locally. I have a linked server that links to itself. I found it really weird that executing sp_executeSQL on the target linked server still resulted in each statement being split up with an sp_resetconnection call.
Aaron Daniels
A: 

As per Remus' answer, but avoids some dynamic SQL using sp_setnetname. YMMV.

This was asked a day or 2 ago: Fully qualified table names with SP_ExecuteSql to access remote server

gbn
I didn't know about sp_setnetname actually. Is a neat trick, but can be dangerous in a concurrent environment, multiple callers can change the name on each other and wreak havoc.
Remus Rusanu
@remus: I used it as a DBA in limited circumstances, to be honest I didn't think it through. I'd use sp_getapplock to control it
gbn
I'm not trying to set the server name as a parameter.
Aaron Daniels
@Aaron: the same technique applies for dynamic server/database names
gbn