2013-08-22 95 views
-1

幾十年來,我已經使用VIEW S作爲同義詞:使用VIEW的Table或View有沒有同義詞的優點?

CREATE VIEW dbo.Banks AS 

SELECT * 
FROM OtherDatabase.dbo.Banks 

我這樣做,所以我可以抽象其中「真正的」表。當它改變時,就像改變視圖一樣簡單:

而且這個效果很好。這不會導致優化器出現任何問題,並且我可以根據需要編輯視圖。

enter image description here

同義詞

與SQL Server 2005開始,微軟引入了同義詞:

CREATE SYNONYM dbo.Banks FOR OtherDatabase.dbo.Banks 

似乎工作相同VIEW方法。我看過的每個執行計劃的行爲都是相同的。

遺憾的是,似乎同義詞無法提供one of their basic functions, functionality i need

提供了一個抽象層,它可以保護基礎對象的名稱或位置所做的更改客戶端應用程序

你無法改變同義詞所指的地方。由於沒有ALTER SYNONYM語句,因此首先必須刪除同義詞,然後重新創建具有相同名稱的同義詞,但將同義詞指向新位置。

他們有任何贖回質量?

實際上,這不會發生。我將永遠不會這樣做。我不會使用一種機制,要求我從數據庫中刪除對象以更改設置。我當然不會刪除所有容易改變的視圖,用SYNONYMs代替它們,並且必須向所有人解釋爲什麼使得一切變得更加困難的原因是「更好」

所以我的問題是,有什麼我失去了使用意見?

  • 每一個執行計劃看起來與同義詞
  • 我可以很容易地改變「視圖同義詞」隨時

有沒有一種美德,以表或視圖的同義詞,我是失蹤?

不必調用 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 '[email protected] 
     PRINT @SQLString 
     EXECUTE sp_ExecuteSQL @SQLString--, @ParmDefinition, @View = @ViewName 
    END 

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

天知道爲什麼SQL Server不能爲我做。

回答

5

一個同義詞是一個更透明的重定向。我更喜歡他們的意見,因爲意見需要維護。特別是在使用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違反了最佳做法。 聳聳肩如果你會接受你的同義詞的掛斷,你將不必擔心。

+0

無法修改同義詞的問題是,無法從UI中更改它們。我不會記住語法。只有當我感覺1337時,我才能親手寫一個'CREATE INDEX';即使這樣,我也需要2或3次嘗試才能正確。 –

+1

@這是一個非常糟糕的藉口恕我直言。與CREATE INDEX相比,CREATE SYNONYM的語法非常簡單。 'CREATE SYNONYM dbo.Something for SomeDatabase.dbo.SomethingElse;' - 這真的很難嗎? –

+2

@IanBoyd懶惰不是不使用某些東西的真正原因。我也願意打賭,這使得你處於少數,因爲大多數嚴肅的SQL開發人員和DBA將所有內容都編寫爲可再生能力。如果我在我的部門發現了一個人使用GUI來處理所有事情,我會因爲A)而感到非常不安,而且B)它需要更長的時間才能完成。 – JNK

0

同義詞對於處理大量不同數據源/多個數據庫等或進行數據遷移的情況很有用。

我從來沒有真正找到理由在新的綠地開發中使用它們。

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 

一個顯著比較模糊的情況下(我們在這裏做所有的時間),如果必須在數據庫中將引用設置爲另一個數據庫中的對象,則不必知道該表中哪些列(動態非規範化)是或將會是什麼,並且您不知道數據庫的名稱在t他在你編寫代碼的時候(每個客戶端一個數據庫,但只有他們簽署合同時)(通常),使用同義詞可能是天賜之物。在創建數據庫時,只需動態構建並運行CREATE SYNONYM myTable FOR <DatabaseName>.<schema>.MyTable,即可完成 - 無論將來爲哪個客戶端添加了哪些列。

+0

+1,用於提及對其他數據庫的引用。在首選項或策略之後命名引用的數據庫並且不必猜測應用程序的名稱是什麼時,這一點尤其重要。 –