-1

几十年来,我一直使用VIEWs 作为同义词:

CREATE VIEW dbo.Banks AS

SELECT *
FROM OtherDatabase.dbo.Banks

我这样做是为了抽象出“真实”表的位置。当它改变时,就像改变视图一样简单:

这很好用。它不会导致优化器出现任何问题,并且我已经能够根据需要编辑视图。

在此处输入图像描述

同义词

从 SQL Server 2005 开始,Microsoft 引入了同义词:

CREATE SYNONYM dbo.Banks FOR OtherDatabase.dbo.Banks

似乎与该方法相同VIEW。我看过的每个执行计划的行为都是一样的。

不幸的是,同义词似乎无法提供它们的基本功能之一,即我需要的功能

提供一个抽象层,保护客户端应用程序免受对基础对象的名称或位置的更改

您无法更改同义词指向的位置。因为没有 ALTER SYNONYM 语句,您首先必须删除同义词,然后重新创建具有相同名称的同义词,但将同义词指向新位置。

他们有什么可赎回的品质吗?

实际上,这不会发生。我永远不会这样做。我不会使用要求我从数据库中删除对象以更改设置的机制。我当然不会删除所有容易更改的VIEW,用 SYNONYM替换它们,并且必须向大家解释为什么让一切变得更难是“更好”

所以我的问题是,使用视图有什么损失吗?

  • 每个执行计划看起来都与同义词相同
  • 我可以随时轻松更改“查看同义词”

我缺少的表或视图同义词有什么优点吗?

除了必须打电话RefreshAllViews以防我忘记我在某处换了桌子

甚至存储过程

我什至不使用存储过程的同义词:

CREATE PROCEDURE dbo.GetUSDNoonRateAsOf @tradeDate datetime AS

EXECUTE OtherDatabase.dbo.GetUSDNoonRateAsOf @tradeDate

我缺少的同义词有什么价值吗?

更新: RefreshAllViews 程序

我们在每个数据库中都有一个标准程序。重新排序或插入列会对视图造成严重破坏;所以他们必须“刷新”

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

天知道为什么 SQL Server 不为我做这件事。

4

3 回答 3

6

同义词是更透明的重定向。我更喜欢它们而不是视图,因为需要维护视图。当你SELECT *特别使用。

我不确定我是否认为缺乏ALTER SYNONYM是一个真正的障碍。同义词的删除/创建是一个非常简单的元数据操作,而且速度非常快。为简洁起见省略错误处理:

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

同样,对于存储过程,如果您的基本存储过程接口发生更改(例如,您添加了一个参数),您还必须更改包装过程 - 同义词并非如此。

一个缺点是您可以在视图上创建一个而不是触发器,但不能在同义词上创建。您无法通过同义词(主要是 DDL)执行其他操作。当然,IntelliSense 可能无法正常运行,具体取决于版本

无法记住语法对我来说似乎是一个编造的借口。没有花哨的选项或 with 子句;只是同义词的 2 部分名称,以及它所指对象的 2、3 或 4 部分名称:

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

如果你不能记住,你是如何创建同义词的?

我还建议彻底简化您的存储过程(并防止它在任何视图不在dbo架构中时失败,或者该过程由默认架构与视图架构不同的人执行,或者视图具有'或名称中的空格,或以其他方式违反标识符的任何规则(您可以在此页面上找到它们):

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

至少,如果您要保留光标,请停止使用糟糕的默认选项(将光标声明为LOCAL FAST_FORWARD,并使用sys.views.INFORMATION_SCHEMA

天知道为什么 SQL Server 不为我做这件事。

因为 SQL Server 是软件,它并不完美——尤其是在依赖关系方面。主要问题是您SELECT *首先在视图中使用违反了最佳实践。耸耸肩如果你愿意接受你对同义词的疑虑,你就不必担心这一点。

于 2013-08-22T14:20:23.243 回答
1

如果一个视图引用了一个表,并且您随后将列添加到该表中,那么您必须修改视图以“拾取”新列——即使您使用SELECT *. 同义词将自动“拾取”这些列。这是一个示例脚本:

--  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

然后,

--  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

(别忘了)

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

一个明显更模糊的情况(我们一直在这里),如果您必须在数据库中设置对另一个数据库中对象的引用,您不一定知道该表中的哪些列(动态非规范化)是或者将是,并且您在编写代码时不知道数据库的名称(每个客户端一个数据库,但只有在他们签署合同后)(通常),使用同义词可能是天赐之物。在创建数据库时,只需动态地构建和运行CREATE SYNONYM myTable FOR <DatabaseName>.<schema>.MyTable,就可以完成——无论将来为哪个客户端添加什么列。

于 2013-08-22T14:22:21.017 回答
0

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.

于 2013-08-22T14:12:27.417 回答