2009-10-29 167 views
40

當談到創建存儲過程,視圖,函數等時,最好是做一個DROP ... CREATE或ALTER對象?DROP ... CREATE vs ALTER

我見過無數的「標準」文件,聲明做DROP ...創建,但我看到許多支持ALTER方法的評論和論據。

ALTER方法保留了安全性,但我聽說DROP ... CREATE方法在第一次執行時強制重新編譯整個SP,而不僅僅是重新編譯語句級別。

有人可以告訴我,如果有其他的優勢/劣勢使用一個在另一個?

+0

後續問題:是DROP ... CREATE還是原子嗎?我假設ALTER是原子的,因爲它是一個單獨的聲明,但也值得驗證。 – gzak 2017-04-20 23:41:30

回答

37

ALTER也會強制重新編譯整個程序。語句級別重新編譯適用於程序中的語句,例如。一個SELECT,因爲基礎表發生變化而重新編譯,而不會對該過程進行任何更改。在ALTER過程中,爲了理解什麼在SQL文本中發生了變化,服務器將不得不...編譯它,甚至不可能有選擇地重新編譯ALTER過程中的某些語句。

對於所有對象,ALTER總是更好,因爲它保留了所有安全性,所有擴展屬性,所有依賴性和所有約束。

+0

更正了錯字:「stetemnts」到「語句」 – 2009-10-29 16:57:39

+2

+1解決了我在問題中提出的兩個問題/要點。 – NYSystemsAnalyst 2009-10-29 18:33:07

8

改變通常更好。如果您刪除並創建,則可能會失去與該對象關聯的權限。

+0

Nono! WITH RECOMPILE告訴SQL Server在每次執行**時都拋出查詢計劃。接下來運行sproc時,所有ALTERS都會導致重新編譯。 – Andomar 2009-10-29 16:47:51

+0

在Andomar的辯護中,我在發表評論後改變了答案。他正在寫信,我正在回答問題的另一部分,我的回答不清楚。 – kemiller2002 2009-10-29 18:19:45

0

您已經提出了一個專門涉及不包含任何數據的DB對象的問題,理論上不應該經常更改。

可能您可能需要編輯這些對象,但不是每5分鐘一次。正因爲如此,我認爲你已經擊掌了頭 - 權限。

簡短的回答,而不是一個真正的問題,只要權限是不是一個問題

48

這是我們如何做到這一點:

if object_id('YourSP') is null 
    exec ('create procedure dbo.YourSP as select 1') 
go 
alter procedure dbo.YourSP 
as 
... 

的代碼創建了一個「存根」的存儲過程,如果它不還沒有存在,否則它會改變。通過這種方式,即使您重複執行腳本,該過程的任何現有權限都會保留。

+1

+1不錯的技巧.. – 2009-10-29 16:57:14

+4

更好的做object_id('dbo.YourSP'),否則你可能最終會改變一個表,除了與另一個所有者不存在 – MartW 2009-10-29 17:05:21

+8

CREATE OR ALTER將會非常適合SQL Server .... ... – 2009-10-29 17:36:19

-1

從可用性的角度來看,下降和創建比改變更好。在不包含該對象但具有IF EXISTS DROP的數據庫中,Alter將失敗,然後CREATE將在具有該對象的數據庫中工作,或者在該對象不存在的數據庫中工作。在Oracle和PostgreSQL中,通常使用CREATE OR REPLACE創建函數和過程,它與SQL SERVER IF EXISTS DROP相同,然後是CREATE。如果SQL Server拿起這個小而非常方便的語法,那將會很不錯。

這就是我該怎麼做的。將所有這些放在一個給定對象的腳本中。

IF EXISTS (SELECT 1 
      FROM information_schema.routines 
      WHERE routine_schema = 'dbo' 
       AND routine_name = '<PROCNAME' 
       AND routine_type = 'PROCEDURE') 
BEGIN 
    DROP PROCEDURE <PROCNAME> 
END 
GO 


CREATE PROCEDURE <PROCNAME> 
AS 
BEGIN 
END 
GO 

GRANT EXECUTE ON <PROCNAME> TO <ROLE> 
GO 
+0

你能解釋一下嗎?我很好奇這是不是有價值的? – Kuberchaun 2009-10-30 21:24:45

+1

我認爲你得到-1是因爲你的陳述被另一個問題駁斥了。基本上有人不同意你的看法。 – jcollum 2010-04-09 18:32:09

1

如果您有一個函數/存儲過程,例如從網站非常頻繁地調用,它可能會導致問題。

存儲過程將被丟棄幾毫秒/秒,在此期間,所有查詢都將失敗。

如果你做了改變,你沒有這個問題。

新創建的存儲過程的模板,通常是這種形式:

IF EXISTS (SELECT * FROM sysobjects WHERE type = 'P' AND name = '<name>') 
    BEGIN 
     DROP PROCEDURE <name> 
    END 
GO 

CREATE PROCEDURE <name> 
...... 

然而,相反的是更好的,IMO:

如果storedproc /功能/等不存在,創建它與一個虛擬選擇語句。然後,修改將始終工作 - 它永遠不會被丟棄。

我們有專門的存儲過程,所以我們存儲的特效/函數通常是這樣的:

EXEC Utils.pAssureExistance 'Schema.pStoredProc' 
GO 

ALTER PROCECURE Schema.pStoredProc 
... 

,我們使用功能相同的存儲過程:

EXEC Utils.pAssureExistance 'Schema.fFunction' 
GO 

ALTER FUNCTION Schema.fFunction 
... 

在Utils.pAssureExistance我們做一個IF並查看「。」後面的第一個字符:如果它是「f」,我們創建一個虛擬函數,如果它是「p」,我們創建一個虛擬存儲過程。

但要小心,如果您創建了虛標量函數,並且您的ALTER位於表值函數上,那麼ALTER FUNCTION將失敗,並說它不兼容。

同樣,Utils.pAssureExistance才能得心應手,另外還有可選參數

EXEC Utils.pAssureExistance 'Schema.fFunction', 'TableValuedFunction' 

將創建一個虛擬的表值函數,

Additionaly,我可能是錯的,但我認爲,如果你做一個放置過程,並且當前正在使用存儲過程的查詢,它將失敗。

但是,alter procedure將等待所有查詢停止使用存儲的proc,然後對其進行更改。如果查詢將存儲過程「鎖定」了太長時間(比如幾秒鐘),ALTER將停止等待鎖定,並改變存儲的過程:使用存儲過程的查詢可能會失敗。

+0

爲什麼不只是檢查「sys.procedures」而不是使用sysobjects(已棄用)並且必須指定類型? – 2009-10-29 17:17:15

+0

「sysobjects」從SQL Server 2008開始被棄用:http://msdn.microsoft.com/en-us/library/ms143729.aspx – 2009-10-29 17:37:16

+0

呃...我使用SQL Server 2008中的模板創建了一個存儲過程,並且複製粘貼它。 微軟應該按照我自己的指導原則! – Kevin 2009-10-30 00:47:15

0

DROP通常會丟失權限和任何擴展屬性。

在某些UDF上,ALTER也將失去擴展屬性(絕對在SQL Server 2005多語句表值函數中)。

我通常不會DROPCREATE除非我也重新創建這些東西(或知道我想失去它們)。

0

當我們在開發中工作時,我們曾經使用alter或者創建新的功能或者修改功能。當我們完成我們的開發和測試後,我們會做一個下降和創建。這可以修改特效日期/時間戳,以便您可以按日期/時間對它們進行排序。

它也使我們能夠看到我們發送的每個可交付成果的日期是多少。

1

我不知道是否可以做出這樣的評論並說「ALTER更好」。我認爲這一切都取決於情況。如果你需要這種細粒度的權限到過程級別,你可能應該在一個單獨的過程中處理這個問題。有必要刪除和重新創建。它清除了現有的安全性並將其重置爲可預測的。

我一直首選使用drop/recreate。我還發現將它們存儲在源代碼管理中更容易。而不是做....如果存在做改變,如果不存在做創建。

說了這些...如果你知道你在做什麼...我不認爲這太重要。

0

如果存在則更好,因爲如果在將腳本移動到QA或測試或生產時有多個環境,則不知道腳本是否已在該環境中存在。通過添加一個drop(如果它已經存在)並且然後添加你將被覆蓋,不管它是否存在。然後,您必須重新申請權限,但最好聽到您的安裝腳本錯誤。

相關問題