使用VIEW,表或视图的同义词是否有任何优点?

时间:2013-08-22 14:04:37

标签: sql-server sql-server-2008-r2 synonym

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

CREATE VIEW dbo.Banks AS

SELECT *
FROM OtherDatabase.dbo.Banks

我这样做,所以我可以抽象出"真正的" 表所在的位置。当它改变时,它就像改变视图一样简单:

这很有效。它没有导致优化器出现任何问题,并且我能够根据需要编辑视图。

enter image description here

同义词

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

CREATE SYNONYM dbo.Banks FOR OtherDatabase.dbo.Banks

似乎与<{1}}方法一起工作相同。我所看到的每个执行计划的行为都相同。

不幸的是,似乎同义词无法提供one of their basic functions, functionality i need

  

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

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

他们有任何兑换质量吗?

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

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

  • 每个执行计划看起来都与同义词相同
  • 我可以随时轻松更改&#34;同义词&#34;

我缺少的表或视图同义词是否有用?

  

除非必须致电VIEW以防忘记我在某处更换了桌子

甚至存储过程

我甚至不使用同义词来存储过程:

RefreshAllViews

我失踪的同义词中是否有值?

更新:RefreshAllViews过程

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

CREATE PROCEDURE dbo.GetUSDNoonRateAsOf @tradeDate datetime AS

EXECUTE OtherDatabase.dbo.GetUSDNoonRateAsOf @tradeDate

上帝知道为什么SQL Server不会为我做这件事。

3 个答案:

答案 0 :(得分:6)

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

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

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

类似地,对于存储过程,如果基本存储过程接口发生更改(例如,添加参数),则还必须更改包装程序 - 而不是同义词。

一个缺点是你可以在视图上创建一个而不是触发器,但你不能在同义词上创建。您还无法通过同义词(主要是DDL)执行其他操作。当然还有IntelliSense may not function correctly, depending on version

无法记住语法似乎是一个伪造的借口。 There are no fancy options or with clauses;只是一个由2部分组成的同义词名称,以及它所引用的对象的2部分,3部分或4部分名称:

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

如果您无法记住,那么您是如何创建同义词的呢?

我还建议彻底简化您的存储过程(并防止它在任何视图不在dbo架构中时失败,或者该过程由默认架构与其不同的人执行视图的架构,或者视图名称中包含'或空格,或以其他方式中断任何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

至少,如果您要保留光标,stop using the terrible default options (declare the cursor as LOCAL FAST_FORWARD)use sys.views instead of INFORMATION_SCHEMA

  

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

因为SQL Server是软件,it isn't perfect - especially when it comes to dependencies。主要问题是您使用SELECT * in your views in the first place违反了最佳做法。 耸肩如果您接受关于同义词的挂断,您将不必担心这一点。

答案 1 :(得分: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,您就完成了 - 无论将来为哪个客户端添加哪些列。

答案 2 :(得分:0)

同义词适用于您处理大量不同数据源/多个数据库等或进行数据迁移的情况。

我从来没有真正找到理由在新的绿地开发中使用它们。