翻譯|使用教程|編輯:楊鵬連|2021-03-31 10:40:15.493|閱讀 297 次
概述:如果SQL Prompt發現使用EXECUTE,則會警告您,而無需指定存儲過程所在的架構,因為它可能導致執行時間變慢,甚至導致運行錯誤的過程。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關鏈接:
SQL Prompt是一款實用的SQL語法提示工具。SQL Prompt根據數據庫的對象名稱、語法和代碼片段自動進行檢索,為用戶提供合適的代碼選擇。自動腳本設置使代碼簡單易讀--當開發者不大熟悉腳本時尤其有用。SQL Prompt安裝即可使用,能大幅提高編碼效率。此外,用戶還可根據需要進行自定義,使之以預想的方式工作。
SQL提示實現了靜態代碼分析規則PE001,該規則將在開發和測試工作期間自動檢查代碼,以查找是否存在通過EXECUTE命令調用存儲過程的情況,而無需指定架構。
即使您不必限定存儲過程的名稱,也就是該過程位于默認模式中時,如果指定該模式,性能也會稍好一些,這會使代碼對其他人更易懂,更一致,而且更容易重構。
任何基于模式的數據庫對象的全名最多包含四個標識符:服務器名稱,數據庫名稱,模式名稱和對象名稱。僅在調用遠程存儲過程時,才需要由所有四個標識符組成的完全限定名稱。如果要在另一個數據庫中調用過程,則顯然需要名稱中的數據庫標識符。在數據庫內,只要過程位于相同的架構中,則只需要對象名稱本身即可。通過指定架構,數據庫引擎需要更少的搜索來識別它。甚至系統存儲過程也應使用“ sys”架構名稱進行限定。同樣在創建存儲過程時,始終指定父架構是一個好習慣。
數據庫對象名稱在服務器中不是唯一的,而在架構中不是唯一的,因此我們需要在適當的時候添加限定符,例如服務器名稱,數據庫名稱或架構名稱,以確保我們可以標識希望執行的過程,毫不含糊。這樣,我們可以避免某些錯誤,最大程度地減少引擎用于搜索過程的時間,并幫助確保對過程的緩存查詢計劃進行重用。
不符合模式的程序存在問題
一個nonschema限定過程名稱將是無論是名稱的一部分,沒有資格,或看起來像一個兩部分名稱,數據庫和對象,與他們之間的雙點在架構名稱丟失。在這種情況下,數據庫引擎必須按以下順序在多個位置搜索以找到所需的過程:
不符合模式要求的過程會引入意想不到的歧義,這可能會導致難以解決的錯誤。過程調用的嵌套越多,出錯的機會就越大。這種歧義也可以防止緩存的查詢計劃被重用。
最好的方法是限定過程名稱,并確保(如果名稱在數據庫中重復)該過程是有意進行的。
模式認證和系統存儲過程
可以從任何數據庫中執行系統存儲過程,Microsoft建議您使用sys模式對它們進行限定,但是如果不這樣做,則不會破壞任何內容。
系統存儲過程的名稱始終以代表特殊的字符sp_開頭,這些過程存儲在Resource數據庫中。它們將出現在該SQL Server實例中所有用戶定義的數據庫的sys模式中。如果您在數據庫中創建與系統存儲過程同名的過程,則無論您如何使用模式名稱對其進行限定,都將永遠不會執行該過程。數據庫引擎始終總是首先在sys模式中搜索。
同一數據庫中的過程名稱重復
如果具有相同名稱的過程位于單獨的模式中,則它們可以完美地共存于同一數據庫中,這樣做是有正當理由的。例如,您可能希望不同類別的用戶通過同一過程調用執行不同的代碼。在這種情況下,每組用戶將需要具有不同的默認架構,該架構存儲了他們的過程版本。用戶將僅對自己的架構具有EXECUTE權限,并使用所有權鏈接來訪問所需的數據。然后,用戶將需要指定不帶模式的過程,以允許SQL Server從用戶的默認模式中選擇存儲過程。
如果您有重復的程序名稱,然后將其變成連架構限定任何過程調用這更重要的不能有歧義!如果沒有,它可能會引入幾乎無法檢測到的錯誤,這些錯誤是在調用錯誤的同義過程時引起的。
SQL Server如何處理非架構限定的過程調用
我們可以通過創建多個具有相同名稱但在不同模式中的存儲過程來演示如何搜索存儲過程。清單1模擬了數據庫中具有三個不同用戶的情況:我自己擁有DBO之類的神力,另外兩個用戶名為The_First_User和The_Second_User。我們為每個用戶分配不同的默認架構,并為他們提供測試程序的不同版本。然后,當它們進行不符合模式資格的過程調用時,我們將看到它們執行哪個版本的過程,以及刪除它們時會發生什么。
/* This script is a series batches that illustrate how the Database engine works out what you want when you don't specify the schema of a stored procedure. The behavior can be quite valuable if you want the same code to be handled differently according to the default schema of the user. Even if you don't have duplicate procedure names, this code shows that the default schema is searched before the DBO schema. */ SET NOCOUNT ON IF Object_Id('dbo.Test_Procedure') IS NOT NULL DROP PROCEDURE dbo.Test_Procedure; GO -- firstly we create a procedure in the DBO schema CREATE PROCEDURE dbo.Test_Procedure @param1 VARCHAR(100) = 'Hello %s', @param2 VARCHAR(100) OUTPUT AS SELECT @param2 = CURRENT_USER + ' is in the ' + Schema_Name() + ' schema, while ' + Replace(Coalesce(@param1, ''), '%s', 'World'); RETURN 0; GO --now we create a procedure with the same name in the MySchema schema IF Object_Id('MySchema.Test_Procedure') IS NOT NULL DROP PROCEDURE MySchema.Test_Procedure; GO --just in case it has been left over from last time IF EXISTS (SELECT schemas.name FROM sys.schemas WHERE schemas.name LIKE 'MySchema') DROP SCHEMA MySchema; GO --we first create the schema CREATE SCHEMA MySchema; GO --now we create the stored procedure in this schema with a different output just so we know which is executed CREATE PROCEDURE MySchema.Test_Procedure @param1 VARCHAR(100) = 'Hello %s', @param2 VARCHAR(100) OUTPUT AS --make the wording different so we can prove which version of the procedure was executed SELECT @param2 = CURRENT_USER + ' is in the ' + Schema_Name() + ' schema, while ' + Replace(Coalesce(@param1, ''), '%s', 'Planet'); RETURN 0; GO --now we create a procedure with the same name in the MyOtherSchema schema IF Object_Id('MyOtherSchema.Test_Procedure') IS NOT NULL DROP PROCEDURE MyOtherSchema.Test_Procedure; GO IF EXISTS (SELECT schemas.name FROM sys.schemas WHERE schemas.name LIKE 'MyOtherSchema') DROP SCHEMA MyOtherSchema; GO CREATE SCHEMA MyOtherSchema; GO ---and in this schema we place a third schema CREATE PROCEDURE MyOtherSchema.Test_Procedure @param1 VARCHAR(100) = 'Hello %s', @param2 VARCHAR(100) OUTPUT AS --make the wording different again, so we can prove which version of the procedure was executed SELECT @param2 = CURRENT_USER + ' is in the ' + Schema_Name() + ' schema, while ' + Replace(Coalesce(@param1, ''), '%s', 'Back yard'); RETURN 0; GO --Now we create a couple of test users whose default schemas are those we've just created IF Database_Principal_Id('The_First_User') IS NOT NULL DROP USER The_First_User; IF Database_Principal_Id('The_Second_User') IS NOT NULL DROP USER The_Second_User; IF Database_Principal_Id('OurPhonyUsers') IS NOT NULL DROP ROLE OurPhonyUsers; GO -- before creating the users we create a role that we can assign to them so that --they can do stuff CREATE ROLE OurPhonyUsers; GRANT EXECUTE ON SCHEMA::MySchema TO OurPhonyUsers; GRANT EXECUTE ON SCHEMA::MyOtherSchema TO OurPhonyUsers; GRANT EXECUTE ON SCHEMA::dbo TO OurPhonyUsers; --comment this out to see what happens! GO --Now we create the users and attach them to the role we created CREATE USER The_First_User WITHOUT LOGIN WITH DEFAULT_SCHEMA = MySchema; EXEC sys.sp_addrolemember N'OurPhonyUsers', N'The_First_User'; EXECUTE AS USER = 'The_First_User'; GO DECLARE @MyMessage VARCHAR(100); --execute the stored procedure without any qualifier as The_First_User EXECUTE Test_Procedure @param1 = 'firstly calling ''hi'' to the %s', @param2 = @MyMessage OUTPUT; SELECT @MyMessage; REVERT; --to being myself GO CREATE USER The_Second_User WITHOUT LOGIN WITH DEFAULT_SCHEMA = MyOtherSchema; EXEC sys.sp_addrolemember N'OurPhonyUsers', N'The_Second_User'; EXECUTE AS USER = 'The_Second_User'; DECLARE @MyMessage VARCHAR(100); --execute the stored procedure without any qualifier as The_Second_User EXECUTE Test_Procedure @param1 = 'Secondly welcoming the %s', @param2 = @MyMessage OUTPUT; SELECT @MyMessage; REVERT; --to being myself GO DECLARE @MyMessage VARCHAR(100); --execute the stored procedure without any qualifier as dbo EXECUTE Test_Procedure @param1 = 'thirdly acknowledging the %s', @param2 = @MyMessage OUTPUT; SELECT @MyMessage; SELECT 'now deleting the MyOtherSchema.Test_Procedure' --now we drop the procedure with the same name in the MyOtherSchema schema IF Object_Id('MyOtherSchema.Test_Procedure') IS NOT NULL DROP PROCEDURE MyOtherSchema.Test_Procedure; GO EXECUTE AS USER = 'The_Second_User'; DECLARE @MyMessage VARCHAR(100); --execute the stored procedure without any qualifier as The_Second_User EXECUTE Test_Procedure @param1 = 'fourthly saying ''greetings'' to the %s', @param2 = @MyMessage OUTPUT; SELECT @MyMessage; --execute the stored procedure with a qualifier as The_Second_User EXECUTE MySchema.Test_Procedure @param1 = 'finally saying hello to the %s', @param2 = @MyMessage OUTPUT; SELECT @MyMessage; REVERT; --to being myself GO ---and clean up DROP PROCEDURE MySchema.Test_Procedure; DROP PROCEDURE dbo.Test_Procedure; DROP USER The_First_User; DROP USER The_Second_User; DROP ROLE OurPhonyUsers; DROP SCHEMA MyOtherSchema; DROP SCHEMA MySchema;清單1
如果執行,將產生以下結果:
----------------------------------------------------------------------------------------
The_First_User is in the MySchema schema, while firstly calling 'hi' to the Planet
----------------------------------------------------------------------------------------
The_Second_User is in the MyOtherSchema schema, while Secondly welcoming the Back yard
-----------------------------------------------------------------------------------------
dbo is in the dbo schema, while thirdly acknowledging the World
-----------------------------------------------------------------------------------------
now deleting the MyOtherSchema.Test_Procedure
-----------------------------------------------------------------------------------------
The_Second_User is in the MyOtherSchema schema, while fourthly saying 'greetings' to the World
-----------------------------------------------------------------------------------------
The_Second_User is in the MyOtherSchema schema, while finally saying hello to the Planet
你怎么看的
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自: