Question

For decades i've used VIEWs as a synonym:

CREATE VIEW dbo.Banks AS

SELECT *
FROM OtherDatabase.dbo.Banks

i do this so i can abstract where the "real" table is. And when it changes, it's as simple as altering the view:

And this works well. It's doesn't cause the optimizer any issues, and i have been able to edit the view as required.

enter image description here

Synonyms

Starting with SQL Server 2005, Microsoft introduced synonyms:

CREATE SYNONYM dbo.Banks FOR OtherDatabase.dbo.Banks

It seems to work identically to the VIEW approach. Every execution plan i've looked at behaves identically.

Unfortunately it seems that synonyms are unable to provide one of their basic functions, functionality i need:

Provides a layer of abstraction that protects a client application from changes made to the name or location of the base object

You are not able to change where a synonym points. Because there is no ALTER SYNONYM statement, you first have to drop the synonym and then re-create the synonym with the same name, but point the synonym to the new location.

Do they have any redeeming quality?

Practically speaking, this isn't going to happen. i will just never do it. i won't use a mechanism that requires me to drop objects from a database in order to change a setting. i'm certainly not going to delete all the easily alterable VIEWs, replacing them with SYNONYMs, and have to explain to everyone why making everything harder is "better".

So my question is, is there anything i am losing by using views?

  • every execution plan looks identical to synonyms
  • i can easily change the "view synonym" at any time

Is there a virtue to a table or view synonym that i'm missing?

Aside from having to call RefreshAllViews in case i forgot that i made a table change somewhere

Even stored procedures

i don't even use synonyms for stored procedures:

CREATE PROCEDURE dbo.GetUSDNoonRateAsOf @tradeDate datetime AS

EXECUTE OtherDatabase.dbo.GetUSDNoonRateAsOf @tradeDate

Is there a value in synonyms that i am missing?

Update: RefreshAllViews procedure

We have a standard procedure in every database. Reordering, or inserting, columns wreaks havoc on views; so they have to be "refreshed".

CREATE PROCEDURE [dbo].[RefreshAllViews] AS

-- This sp will refresh all views in the catalog. 
--     It enumerates all views, and runs sp_refreshview for each of them

SET NOCOUNT ON

DECLARE abc CURSOR FOR
     SELECT TABLE_NAME AS ViewName
     FROM INFORMATION_SCHEMA.VIEWS
     ORDER BY newid()
OPEN abc

DECLARE @ViewName varchar(128)
--DECLARE @ParmDefinition NVARCHAR(500)

-- Build select string once 
DECLARE @SQLString nvarchar(2048)
--SET @SQLString = N'EXECUTE sp_RefreshView @View'
--SET @ParmDefinition = N'@View nvarchar(128)'

FETCH NEXT FROM abc 
INTO @ViewName
WHILE @@FETCH_STATUS = 0 
BEGIN
    IF @ViewName <> 'IndexServerNodes'
    BEGIN
        SET @SQLString = 'EXECUTE sp_RefreshView '+@ViewName
        PRINT @SQLString
        EXECUTE sp_ExecuteSQL @SQLString--, @ParmDefinition, @View = @ViewName
    END

    FETCH NEXT FROM abc
    INTO @ViewName
END
CLOSE abc
DEALLOCATE abc

God knows why SQL Server doesn't do it for me.

Was it helpful?

Solution

A synonym is a much more transparent redirect. I prefer them over views because views need to be maintained. When you use SELECT * especially.

I'm not sure I buy that the lack of ALTER SYNONYM is a real blocker. The drop/create of a synonym is a very simple metadata operation, and will be very fast. Omitting error handling for brevity:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
  DROP SYNONYM ...
  CREATE SYNONYM ...
COMMIT TRANSACTION;

Similarly, for stored procedures, if your base stored procedure interface changes (say, you add a parameter), you have to also change the wrapper procedure - not so with a synonym.

One downside is that you can create, say, an instead of trigger on a view, but you can't on a synonym. There are other operations you can't perform via a synonym (mostly DDL). And of course IntelliSense may not function correctly, depending on version.

Not being able to memorize the syntax seems like a made-up excuse to me. There are no fancy options or with clauses; just a 2-part name for the synonym, and a 2-, 3- or 4-part name for the object it refers to:

CREATE SYNONYM dbo.Something FOR Server.Database.dbo.SomethingElse;

If you can't memorize that, how did you create the synonym in the first place?

I also have a suggestion to thoroughly simplify your stored procedure (and prevent it from failing when any view is not in the dbo schema, or the procedure is executed by someone whose default schema is not the same as the view's schema, or the view has an ' or space in its name, or otherwise breaks any of the rules for identifiers (you can find them on this page)):

CREATE PROCEDURE [dbo].[RefreshAllViews] 
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @sql NVARCHAR(MAX) = N'';

  SELECT @sql += '
    EXEC sp_refreshview ' + CHAR(39) 
    + QUOTENAME(REPLACE(s.name,'''','''''')) 
    + '.' + QUOTENAME(REPLACE(v.name,'''','''''')) + CHAR(39) + ';'
  FROM sys.views AS v
  INNER JOIN sys.schemas AS s
  ON v.[schema_id] = s.[schema_id];

  PRINT @sql;
  EXEC sp_executesql @sql;
END
GO

At the very least, if you're going to keep the cursor, stop using the terrible default options (declare the cursor as LOCAL FAST_FORWARD), and use sys.views instead of INFORMATION_SCHEMA.

God knows why SQL Server doesn't do it for me.

Because SQL Server is software, and it isn't perfect - especially when it comes to dependencies. The main problem is that you are violating a best practice by using SELECT * in your views in the first place. shrug If you would accept your hang-ups about synonyms, you won't have to worry about that.

OTHER TIPS

If a view references a table, and you subsequently add columns to that table, you must modify the view in order to “pick up” the new column—even if you use SELECT *. Synonyms will “pick up” those columns automatically. Here’s a sample script:

--  Set things up
CREATE TABLE Foo
 (
   Id   int          not null
  ,data varchar(10)  not null
 )
GO

INSERT Foo values (1,'one'),(2,'Two')
GO


CREATE SYNONYM synFoo for Foo
GO


CREATE VIEW vFooDelim as select Id, Data from Foo
GO

CREATE VIEW vFooStar as select * from Foo
GO

select * from Foo
select * from synFoo
select * from vFooDelim
select * from vFooStar

then,

--  Add a column
ALTER TABLE Foo
 add MoreData datetime default getdate()
GO

select * from Foo
select * from synFoo
select * from vFooDelim
select * from vFooStar
GO

(don’t forget to)

--  Clean things up
DROP Synonym synFoo
DROP VIEW vFooDelim
DROP VIEW vFooStar
DROP TABLE Foo

A significantly more obscure situation (that we do all the time here), if you have to set up a reference in a database to an object in another database, you don’t necessarily know what columns are in that table (dynamic denormalized) are or will be, and you don’t know the name of the database at the time you write your code (one database per client, but only once they sign the contract) (usually), using synonyms can be a godsend. At the time of database creation, just dynamicaly build and run CREATE SYNONYM myTable FOR <DatabaseName>.<schema>.MyTable, and you are done—no matter what columns get added for which client in the future.

Synonyms are useful for situations where you're working with lots of disparate data sources/multiple databases etc, or doing data migrations.

I've never really found cause to use them in new, greenfield developments.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top