翻譯|使用教程|編輯:楊鵬連|2021-02-04 11:11:30.217|閱讀 213 次
概述:通常,應通過在每個存儲過程,觸發器和動態執行的批處理的開始處添加SET NOCOUNT ON來防止發送行數消息。Phil Factor演示并解釋了細微差別和例外。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關鏈接:
SQL Prompt是一款實用的SQL語法提示工具。SQL Prompt根據數據庫的對象名稱、語法和代碼片段自動進行檢索,為用戶提供合適的代碼選擇。自動腳本設置使代碼簡單易讀--當開發者不大熟悉腳本時尤其有用。SQL Prompt安裝即可使用,能大幅提高編碼效率。此外,用戶還可根據需要進行自定義,使之以預想的方式工作。
SQL提示實現了兩個靜態代碼分析規則,以檢查代碼是否可能濫用該SET NOCOUNT命令:
默認情況下,在SQL Server實例級別SET NOCOUNT設置為OFF,這意味著DONE_IN_PROC將針對存儲過程中的每個語句將消息發送到客戶端。當使用提供與Microsoft SQL Server執行查詢公用事業,消息“NN行受到影響”將默認,在Transact-SQL語句,如年底顯示SELECT,INSERT,UPDATE,和DELETE。
Microsoft建議在會話級別上有選擇地使用SET NOCOUNT ON來防止發送這些消息:“對于包含多個不返回大量實際數據的語句的存儲過程,消除這些消息可以顯著提高性能,因為網絡通信量很大。大大減少”。
通常,最好的方法是阻止發送行計數消息(除非需要發送它們),但棘手的部分是容納使用并經常濫用這些消息的舊版應用程序。此外,對于數據庫應用程序(例如ORM)的中間層對過程的異步處理,發送這些消息有時可能會成為問題。與存儲過程的結果相比,行計數消息傳輸到客戶端的速度要慢得多,這可能會阻塞線程。
什么是訊息?
與數據庫的連接分別傳遞數據和消息。在Management Studio(SSMS)中,當查詢結果呈現為網格時,它們由查詢窗口中的單獨窗格表示。進行sqlClient連接時,InfoMessage處理程序可以讀取消息流。為了使客戶端能夠讀取和處理服務器發送的警告或消息,客戶端可以通過可以響應這些事件的SqlInfoMessageEventHandler委托來偵聽這些消息。
在本文中,我們僅關注一種類型的消息。行數。但是,SQL Server也可以發送消息以響應特定的命令。連RAISERROR(10或更低的嚴重程度),以及PRINT報表和SET STATISTICS語句的三人組(SET STATISTICS IO ON,SET STATISTICS TIME ON,SET STATISTICS XML ON)。我的文章《不熱情的測試人員的常規SQL DML測試》說明了監視性能時使用此消息流的價值。該SET NOCOUNT命令僅確定是否發送行計數消息。
多個應用程序,組件,小部件(例如網格)和中間件(例如ORM)使用rowcount消息來獲取當前數據結果的計數,即使在相同的情況下通常很難將查詢與count消息進行匹配會話會執行很多其他查詢,這也可能導致線程阻塞。最好在過程的返回碼中或通過輸出變量使用來關閉這些SET NOCOUNT ON行計數消息并使用值返回計數@@ROWCOUNT。但是,有許多舊代碼需要容納。
SET NOCOUNT設置的范圍是什么?
與SQL Server建立連接并啟動會話后,只需設置NOCOUNT一次,這將影響您在該會話中所做的一切。SET您所做的陳述將僅更改當前會話對特定信息的處理;您在該會話中執行的每個批處理都將繼承這些設置。
如果SET在存儲過程或觸發器中運行語句,SET則從存儲過程或觸發器返回控制后,將恢復該選項的先前值。同樣,如果SET NOCOUNT在動態SQL字符串中有一條通過使用sp_executesql或來運行的語句EXECUTE,則在SET執行動態SQL字符串后將還原該選項的初始值。因此,無需NOCOUNT在存儲過程或觸發器的末尾顯式設置。
除了過程,觸發器和動態執行的批處理之外,NOCOUNT會話中的所有設置都會保留在會話中,直到更改為止。
SET NOCOUNT ON的性能優勢是什么?
使用精心設計的存儲過程,您將只能通過覆蓋的默認服務器范圍設置來獲得微不足道的性能提升NOCOUNT。也就是說,在特殊情況下,使用SET NOCOUNT ON將帶來巨大收益。這完全取決于在過程中執行的查詢的數量和頻率。例如,如果某個過程正在使用游標執行許多查詢,這些查詢的結果隨后構成返回的查詢的一部分,或者該過程包含許多未返回大量實際數據的語句,則該過程可以執行與相比,速度提高了十倍NOCOUNT OFF,因為網絡流量大大減少了。在過程中僅執行一兩個查詢,收益將不到5%。
為什么不只在數據庫實例級別啟用NOCOUNT?
的用戶選項服務器配置設置指定“全局缺省”為每個SET選項,包括NOCOUNT。默認情況下,SQL Server實例將被NOCOUNT禁用,因此針對該實例上的數據庫發出的每條語句將導致最后返回一條消息,指出受影響的行數。
您可以使用來修改實例級別的行為,從而啟用NOCOUNT并阻止發送這些消息sp_configure,如清單1所示。這將影響在進行設置之后啟動的所有用戶會話的默認設置。
EXEC sys.sp_configure 'user options', '512'; -- 512 = NOCOUNT清單1
用戶可以通過發出SET NOCOUNT僅影響其單個會話的語句來覆蓋服務器級別的默認值。
觸發器不應發送行數消息;這條規定沒有例外。實際上,如果中間應用程序層期望某些行計數消息,并且將其SET NOCOUNT OFF用于觸發器,則可能會導致奇怪的隨機錯誤。甚至SSMS的數據網格也可能觸犯觸發問題。
但是,在其他地方,也有很多例外。如果您有任何舊組件使用返回的rowcount消息訪問數據庫,則在實例級別阻止這些消息可能會導致問題。通常,可以通過NOCOUNT針對這些組件正在使用的存儲過程進行適當設置來輕松地容納這些組件。但是,如果他們直接訪問表,并且您無法SET NOCOUNT OFF為這些會話添加,則更改數據庫實例級別的設置將是不明智的。
同樣,如果應用程序中的某個組件(例如ORM或LINQ)正在濫用此消息來確定結果的行數,那么如果您關閉消息,則可能會發生一些不良情況。
如果您開啟NOCOUNT,會有什么壞處?
如果使用DataAdaptor調用SQL Server存儲過程來編輯或刪除數據,請不要SET NOCOUNT ON在存儲過程定義中使用。這將導致受影響的行計數返回為零,并且DataAdapter拋出DBConcurrencyException。實際上,明智的防御性編程將意味著SET NOCOUNT OFF在這些情況下發布明確的建議。
該sqlclient.sqlcommand類還可以遇到與問題SET NOCOUNT ON,可能是由客戶端使用ODBC的方式造成。當應用程序調用SQLRowCount時,行計數消息在ODBC中可用。這不是可靠的信息,因為某些數據源無法在獲取結果之前返回結果集中的行數。
即使在SQL Server中,僅當您NOCOUNT在讀取SQLRowCount之后隨后測試“狀態”時,此值才可靠。當NOCOUNT選項設置為on,然后SQLROWCOUNT返回0,即使有結果。如果SQLRowCount返回0,則應用程序應通過測試特定于SQL Server的屬性的值來確定是否NOCOUNT為。如果返回該值,則SQLRowCount的值為0僅表示SQL Server未返回行數。如果返回,則表示已關閉,SQLRowCount中的值為0ONSQL_SOPT_SS_NOCOUNT_STATUSSQL_NC_ONSQL_NC_OFFNOCOUNT 指示該語句不影響任何行,因此不需要處理結果。
那么,什么是“最佳實踐”建議?
可行的簡單建議是保持數據庫實例級別的默認狀態不變,并SET NOCOUNT ON在每個存儲過程,觸發器和動態執行的批處理的開始處添加一個。此規則將毫無例外地適用于所有觸發器。存儲過程也將不需要這些消息,除非被試圖使用它們來獲取結果行數的應用程序從數據庫外部調用它們。通常,最好使用@@ RowCount中的值將計數發送到輸出變量中,但這無助于預先存在的應用程序組件。如果需要確保查詢返回行計數消息,則應指定它而不是采用當前設置。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自: