What does SSMS use to create a linked SQL Server by name? - sql-server

We have several SQL servers set up in my workplace that are all linked to each other and we make use of 4-part DB names in a lot of our code. We are considering moving some of our databases from one server to another and are assessing the impact on our code, however no one here seems to know beyond the Linked Server Name what protocol is used in the [server] portion of the 4pt DB name [server].[database].[dbo].[table]. Is the [server] portion a WINS entry, is it simply DNS, or is SQL Server doing something clever on it's own to get there?
If it's DNS, it will be simple enough to move the DB's (minimal code changes), but anything else and we may have to reconsider our strategy.

server is just a symbolic name, the datasrc is what really matters.
Suppose you have a linked server created like this:
EXEC master.dbo.sp_addlinkedserver #server = N'TEST', #srvproduct=N'', #provider=N'SQLNCLI', #datasrc=N'server2008r2'
and the queries select from TEST.database.schema.table. Recreate the linked server with different #datasrc and it will still work, but this time it would read data from a different physical server (as long as the data is there and the security is set up right).

Related

SQL Server How to add a linked server to the same instance without performance impact

in my company, we have several environments with MS SQL database servers (SQL 2008 R2, SQL 2014). For the sake of simplicity, let us consider just a TEST environment and a PROD environment and two sql servers in each. Let the servers be called srTest1, srTest2, srProd1, srProd2 and each be running a default MS SQL Server instance. We work with multiple databases, say DataDb, ReportDb, DWHDb.
We want to keep the same source code in T-SQL for both TEST and PROD, but the problem is the architecture or distribution of the above mentioned databases in each environment:
TEST:
srTest1 - DataDb
srTest2 - DWHDb, ReportDb
PROD:
srProd1 - DataDb, ReportDb
srProd2 - DWHDb
Now, say, in ReportDb, we write stored procedures with many SELECTs referencing tables and other objects in DataDb and DWHDb. In order to have source code as universal as possible, we decided to create linked servers for each database on each db server in each environment and name them with respect to the database they're created for. Therefore, there'll be these linked servers:
lnkDataDb, lnkReportDb and lnkDWHDb on srTest1,
lnkDataDb, lnkReportDb and lnkDWHDb on srTest2,
lnkDataDb, lnkReportDb and lnkDWHDb on srProd1,
lnkDataDb, lnkReportDb and lnkDWHDb on srProd2.
And we'll adjust the source in the stored procs accordingly. For instance:
Instead of
SELECT * FROM DataDb.dbo.Contact
We'll write
SELECT * FROM lnkDataDb.DataDb.dbo.Contact
The example above is reasonable for a situation where the database from which you execute the query (ReportDb) lies on a different server than that with the referenced table (DataDb). Which is the case for the TEST environment. But not so in PROD. It is performance I'm here concerned about. The SQL Server will treat that SELECT as a "remote query" no matter whether, in fact, it is a reference to a local object or not.
Now, it comes the most important part:
If you check these 3 queries for their actual execution plans, you'll see an interesting thing:
(1) SELECT * FROM DataDb.dbo.Contact
(2) SELECT * FROM srProd1.DataDb.dbo.Contact
(3) SELECT * FROM lnkDataDb.DataDb.dbo.Contact
The first two (query #1 and #2) have the same execution plan (the fastest possible) even if you use the four-part name manner of referencing the table Contact in #2.
The last query has a different plan (remote query, thus slower).
The question is:
Can you somehow create a linked server to self (the same sql server instance, the default instance actually) as an "alias" to the name of the host (srProd1) in order for the SQL server to be forced to understand it as local and not issue "remote execution" plans?
Thanks a lot for any hints
Pavel
Recently I found a workaround which seems to solve this kind of issues more efficiently and more elegantly than the solution with self-pointing linked servers.
If you work (making reports, for example) with multiple databases on multiple SQL servers and the physical distribution of the databases on the servers is a challenge since it may differ from one environment to another (e.g. TEST vs PROD), I suggest this:
Use three-part db object names whenever possible. If the objects are local, then execution plans are also local, and thus effective.
Example:
SELECT * FROM DataDb.dbo.Contact
If you happen to run the above query from within a different SQL server instance (residing on a different physical machine, for example, but this not necessarily, the other SQL server instance could be installed even on the same machine), briefly if you're about to use a four-part name:
SELECT * FROM lnkDataDb.DataDb.dbo.Contact
Then you can circumvent that using the following trick:
Let's assume lnkDataDb points to srTest2 and you're executing your queries from srTest1. Now, you'll create a "fake" database DataDb on your local server (srTest1). This fake DataDb shall contain no real db objects (no tables, no views, no stored procedures, no UDFs etc.). There shall only be synonyms defined in it. (And there also shall be the same schemas in it as those in the real DataDb on srTest2). These synonyms shall be named exactly the same way as their real db-object counterparts in DataDb on srTest2. Example:
-- To be executed on srTest1.
EXEC sp_addlinkedserver
#server = N'lnkDataDb',
#srvproduct = N'',
#provider = N'SQLNCLI',
#datasrc = N'srTest2'
;
GO
CREATE DATABASE [DataDb];
GO
USE [DataDb];
GO
CREATE SYNONYM dbo.Contact FOR lnkDataDb.DataDb.dbo.Contact;
GO
Now, if you want to SELECT rows from the table dbo.Contact residing in the database DataDb on srTest2 and you're executing your query from srTest1, you'll use a simple three-part table name:
SELECT * FROM DataDb.dbo.Contact
Of course, on srTest1, this is not a table, that's just a synonym referencing the same-named table on srTest2. However, that's the trick, you use the same query syntax as if you were executing it on srTest2 where the real db object resides.
There are disadvantages of this approach:
On the local server, at the beginning, there must not be a database
with the same name as the remote one. Because you're about to create
a "fake" database with that name to reflect the names of remote
db objects.
You're creating one database that is almost empty, thus
increasing the mess of various databases residing on your local
SQL server. This might provoke reluctance of your database admin
if they prefer having as few databases as possible.
If you're developing your T-SQL scripts in SQL Server Management
Studio, for example, using synonyms cuts you off from the convenience
of the IntelliSense feature.
Advantages outweigh the above-mentioned disadvantages, though:
Your scripts work in any environment (DEV, TEST, PROD) without
the need to change any part of the source code.
If the other database you're querying data from resides on the same
SQL server instance as your script, you also use the three-part name
convention and your SQL server evaluates the query in execution plan
as local which is OK. (This is what the original question of this
post was searching to solve.)
If the other database you're querying data from resides on another
SQL server instance, you still use a "local syntax manner" of a SQL
query (with the synonym) which, only at runtime, evaluates in
a remote execution plan. Which is also fine because the db object
actually is remote.
To summarize
The query executes as local if the referenced object is local, the query executes as remote if the referenced object is remote, but the T-SQL script is always the same. You don't have to change a letter in it.

Querying multiple MS SQL database instances on the same machine

I am new to MS SQL and I am trying to do something that seems simple but is driving me crazy.
I want to write a query to pull data from two databases. Each database is on a different instance on the same DEV machine. (one is MS SQL 2008 and the other MS SQL 2005). I am using the Microsoft SQL Server Management Studio (MSSMS).
I have the basics figured out. I know the format of the query and what I need to do. My big problem is figuring out what the NAME of each server is?
SELECT LastName
FROM [servername1].CHA2.dbo.Customer
UNION
SELECT LastName
FROM [servername2].OBXKites.dbo.Contact
ORDER BY LastName
I used the server name that I connect to MSSMS (DLPT\HENRY) with and what is also returned by ##SERVERNAME
SELECT ##SERVERNAME returns DLPT\HENRY
I tried
DLPT\HENRY.CHA2.dbo.Customer
did not work
I tried it without the DLPT HENRY.CHA2.dbo.Customer
did not work
I need to future out what the NAME of the server is to use in the query.
[DLPT\HENRY].CHA2.dbo.Customer
The namo contains a backslash which is normally illegal in an identifier. You surround illegal names with brackets.
Note that you surround just the server name. In other words, it is [DLPT\HENRY].CHA2.dbo.Customer, not [DLPT\HENRY.CHA2.dbo.Customer].
You have to configure Linked servers. Then only different instances of SQL Server are able to communicate with each other.
Unfortunately you can't access tables in databases in separate SQL Server instances by default. You have a couple of options here - neither are simple and might require help from a DBA:
1) Use linked servers like this:
http://technet.microsoft.com/en-us/library/ff772782(v=sql.110).aspx
Then you will be able to refer to the second table in the format INSTANCENAME.DatabaseName.SchemaName.TableName
2) Use replication to get the table from the second database into the first database. Then the contents of the second table will be synched to the first database in more or less real time
Read about SQL Replication here

Openrowset vs. Linked server

In my work area we have 100+ MS SQL databases across the country from where we need to query data back to a single SQL db. We can do this either by using OpenRowSet or LinkedServer. But which one should be used.
Openrowset is ad-hoc. So connection have to be established every time openrowset is called. This should have some extra overhead on performance.
On the other hand Linked Server is persistent. So no need to establish connection every time (i guess). But the central server does have to have all those linked servers added to it. Will adding so many linked servers have any negative impact on the server?
Bottom line is that for connecting to a lot of servers on monthly basis, which will be better approach? openrowset or linked server?
As I recall, OpenRowSet executes the query on the remote server, whereas Linked Server makes the join locally. (Much more resource-intensive than 'connection' concerns.)

SQL Server 2008 R2 - Running a Stored Procedure against Linked Servers

I am trying to create a SQL Job that sits on what I like to call a Maintenance Server where details about all the other server databases sit. So I have a stored procedure to gather all the required data I have and this stored procedure is now in MaintenanceServer.MaintenanceDB.pr_MyProcedure.
Now what i'd like to do this is. I am creating Linked Servers on my MaintenanceServer which points to all the other Servers I'd like to maintain. Next on my list is to be able to run this procedure pr_MyProcedure against all those LinkedServers. I have over 25 servers to maintain and what i want to do is to run the procedure against them and insert the result to my local MaintenanceDB.
Can someone point me to a good way to do this? Also i'd like to hear the drawbacks of this method.
Thanks and Cheers!
EDIT:
I was also thinking about storing the SP on all the master databases of my other Servers and running them remotely on my Maintenance Server. Then i'll use OPENQUERY() to gather all the results that I need. However, I don't think I want to touch all the master databases on my server list. Please tell me if this would be better than the once I stated above.
The nice way to do it is run the SP on the target server, as that's nicely modular. If you want to query the remote server, it's going to be more painful. I'm not sure whether the undocumented sp_foreachdb deals with linked databases, if not you are down to dynamic sql.
As in build a string and call it with Exec(#somesql), that will need to deal with the results itself, as any variables will only be in scope inside the exec.
Personally I'd consider inverting all this. Have each server call it's own SP and the call an SP on the maintenance box to store the results.
EXEC [RemoteServer] .DatabaseName.DatabaseOwner.StoredProcedureName
‘Params’
Example:
EXEC [RemoteServer] .DatabaseName.DatabaseOwner.StoredProcedureName ’PramValue’

Making Microsoft Access Tables in SQL Server Identical on different setups

I have just noticed that one of the views I create from Microsoft Access in SQL Server via a linked server is interpreted differently in different machines/setups etc.
Example:
EXEC sp_addlinkedserver acc465tghv, 'OLE DB Provider for Jet', 'Microsoft.Jet.OLEDB.4.0', 'C:\tester.mdb'
EXEC sp_addlinkedsrvlogin acc465tghv, TRUE
GO
CREATE VIEW TI265 AS SELECT * FROM acc465tghv...TI0CE
When I open the access database in a different machine/computer, the date is formatted differently and I am sure other data types may be formatted/interpreted different when you open the same database (.mdb file) in different machines/computers with different versions of Access and setups etc.
The question is, how can I create a view or a table that shows the access table exactly the same in SQL server?
What options or work arounds are there?
Thanks all
This is pretty standard SQL Server behaviour, based on some functions being deterministic and others non-deterministic. You can read up a bit more about the various functions here.
You can also use SET DATEFORMAT to specify the format in which strings are interpreted by SQL Server.
However, in this scenario, it's pretty likely that the client machine is the thing that is formatting the date differently, based on it's Locale.

Resources