2009-09-27 158 views
238

通過this question那裏有關於SET NOCOUNT不同觀點的啓發......SET NOCOUNT ON使用

我們應該使用SET NOCOUNT ON的SQL Server?如果不是,爲什麼不呢?

編輯6什麼,在2011年7月22日

它抑制任何DML後的 「XX行受到影響」 消息。這是一個結果集,當發送時,客戶端必須處理它。它很小,但可以測量(請參閱下面的答案)

對於觸發器等,客戶端將收到多個「受影響的xx行」,這會導致某些ORM,MS Access,JPA等所有錯誤形式(請參閱下面的編輯)

背景:

一般公認的最佳實踐(我想,直到這個問題)是觸發條件和SQL Server存儲過程使用SET NOCOUNT ON。我們在任何地方都使用它,並且快速的谷歌顯示了許多SQL Server MVP也同意。

MSDN說這可以打破.net SQLDataAdapter

現在,這意味着SQLDataAdapter僅限於完全簡單的CRUD處理,因爲它期望「n行受影響」消息匹配。所以,我不能用:

  • IF的存在是爲了避免重複(沒有行受影響的消息)注:謹慎使用
  • WHERE NOT EXISTS(再少點行預計
  • 過濾掉瑣碎的更新(例如,沒有數據實際上改變)
  • 之前(如日誌記錄)
  • 隱藏複雜性或denormlisation
  • 做任何訪問表0

在問題marc_s(誰知道他的SQL的東西)說不要使用它。這與我認爲的不同(我也認爲我自己在SQL方面也有點勝任)。

這可能是我錯過了一些東西(隨意指出明顯的),但是你有什麼想法?

注意:我看到這個錯誤已經有好幾年了,因爲我現在不使用SQLDataAdapter。

編輯的意見和問題後:

編輯:更多的想法...

我們有多個客戶端:一個可以使用C#SQLDataAdaptor,另一個可以使用NHibernate的從Java。這些可能會以不同的方式影響SET NOCOUNT ON

如果您將存儲的過程視爲方法,那麼假定某些內部處理以某種方式適用於您自己的目的,這是錯誤的形式(反模式)。

編輯2:一個trigger breaking nHibernate question,其中SET NOCOUNT ON不能設置

(不,它不是this一式兩份)

編輯3:然而,更多的信息,感謝我的MVP同事

編輯4:2011 5月13

Breaks Linq 2 SQL too when not specified?

編輯5:2011 14 6

符JPA,存儲過程與表變量:Does JPA 2.0 support SQL Server table variables?

編輯6:2011年8月15日

SSMS「編輯行」數據網格需要SET NOCOUNT ON:Update trigger with GROUP BY

編輯7:2013年3月7日

更深入的細節從@RemusRusanu:
Does SET NOCOUNT ON really make that much of a performance difference

+0

@AlexKuznetsov:什麼是「Threadsafe」方法?在EXISTS中執行的讀取仍然會包含任何未完成的交易? – AnthonyWJones

+0

SET NOCOUNT隻影響「(受影響的#記錄)」消息的顯示,而不影響@@ ROWCOUNT的底層值或數據庫引擎本身。如果EXISTS和WHILE NOT EXISTS將無論如何工作。 –

+1

@Jeremy Seghi:對於遲到的回覆感到抱歉。 (#rows affected)消息是由SSMS等解釋的客戶端工具東西:但是有一個數據包與此信息一起發送。當然,我知道@@ rowcount是如何工作的,但這不是問題的關鍵...... – gbn

回答

146

好吧,現在我已經做了我的研究,這裏是交易:

所以我認爲你可以SET NOCOUNT ON的堅持,如果成本小於切換到另一種技術。我仍然會考慮放棄SqlDataAdapter,因爲你仍然不知道接下來會遇到什麼樣的設計怪癖。

編輯:@racingsnail指出,網絡往返延遲是比數據包大小更大的性能殺手。他有一點,但第二個網絡數據包不會產生與往返延遲相同的延遲,因爲數據包將串聯發送,並且不需要確認。所以它可能會導致比實際的網絡往返延遲少得多的延遲。

編輯2:下面是關於SET NOCOUNT設置微不足道的開銷非常詳細的分析:http://daleburnett.com/2014/01/everything-ever-wanted-know-set-nocount/

+0

確實。我一直使用SET NOCOUNT ON,但是marc_s在另一個問題中指出了SQLDataAdapter的侷限性。 – gbn

+0

謝謝。字節或大小對我來說不是問題,但客戶端必須處理它。這是SQLDataAdapter的依賴,但仍令我驚訝,雖然... – gbn

+0

我沒有任何客戶端處理開銷基準,但我想處理9個字節不會那麼複雜或繁瑣。 –

28

我想在一定程度上它是一個DBA與開發人員的問題。

作爲一個開發大多數人,我會說不要使用它,除非你絕對必須 - 因爲使用它可以打破你的ADO.NET代碼(如微軟所記錄的)。

而且我想作爲一名DBA,你會在另一邊更加努力 - 儘可能地使用它,除非你真的必須阻止它的使用。

此外,如果你的開發者曾經使用「RecordsAffected」通過ADO.NET的ExecuteNonQuery方法調用返回,你就麻煩了,如果每個人都使用SET NOCOUNT ON因爲在這種情況下,會的ExecuteNonQuery總是返回0

而且請參閱Peter Bromberg的blog post並查看他的位置。

所以它真的歸結到誰得到規定的標準:-)

馬克

+0

他是關於簡單的CRUD,雖然:他提到的數據網格可以使用XML發送多行,以避免往返等 – gbn

+0

我想如果你從來沒有使用SqlDataAdapters,並且您從不檢查並依賴ExecuteNonQuery返回的「記錄受影響」編號(例如,如果您使用Linq-to-SQL或NHibernate),那麼在所有存儲的特效中使用SET NOCOUNT ON可能沒有任何問題。 –

5

關於觸發器打破NHibernate的,我有這樣的親身體驗。基本上,當NH進行更新時,它期望受到一定數量的行影響。通過將SET NOCOUNT ON添加到觸發器,可以將行數返回到NH預期的數量,從而解決問題。所以是的,如果你使用NH,我肯定會推薦關閉觸發器。

關於SP中的用法,這是個人喜好的問題。我一直在排倒數,但再一次,沒有任何真正有力的論據。

在另一個說明中,你應該考慮從基於SP的架構中移走,那麼你甚至不會有這個問題。

+1

我不同意遠離存儲的特效。這意味着我們必須在2個不同的客戶端代碼庫中擁有相同的SQL,並相信我們的客戶端編碼器。我們是開發人員DBA。你不是指「SET NOCOUNT * ON *」嗎? – gbn

+6

關於SP vs no-SP,已經完成了...... ;-) – gbn

+0

@gbn您可以在SP上選擇一些優秀的文章,而不是SP請 – Coops

10

如果您在說可能有不同的客戶端,那麼如果SET NOCOUNT未設置爲ON,則傳統ADO會出現問題。

我經常遇到一個問題:如果一個存儲過程執行一些語句(因此會返回一些「xxx rows affected」消息),ADO似乎不會處理這個並引發錯誤「無法更改ActiveConnection一個Recordset對象的屬性,它具有一個Command對象作爲其源。「

所以我一般主張把它設置爲ON,除非有一個確實是的好理由。你可能已經找到了真正的好理由,我需要去閱讀更多內容。

64

我花了很多時間在NOCOUNT上找到真正的基準數據,所以我想我會分享一個快速總結。

  • 如果您的存儲過程使用遊標執行大量非常快速的操作而沒有返回結果,那麼擁有NOCOUNT OFF可能需要將其打開約10倍。 1這是最壞的情況。
  • 如果您的存儲過程僅執行一次快速操作而沒有返回結果,則設置NOCOUNT ON會使性能提升3%左右。 2這將與典型的插入或更新過程一致。
  • 如果您的存儲過程返回結果(即您選擇了某個內容),則性能差異將隨着結果集的大小成比例地減小。
+4

+1對於光標的影響,這與我觀察到的 – zvolkov

9

在使事情更加複雜的風險,我鼓勵略有不同的規則,所有這些我看到上面:

  • 總是在一個進程的頂部設置NOCOUNT ON,你做任何工作之前, proc,但總是SET NOCOUNT OFF再次,從存儲的過程返回任何記錄集之前。

所以「通常保持nocount,除非你實際返回結果集」。我不知道這會破壞任何客戶端代碼的任何方式,這意味着客戶端代碼永遠不需要知道任何關於proc內部的東西,而且它並不是特別繁重。

+0

一致謝謝。當然可以從DataSet或使用容器中獲取rowcount,但可能會有用。我們在SELECT上不能有觸發器,所以這是安全的:大多數客戶端錯誤是由數據更改上的虛假消息引起的。 – gbn

+0

這個規則的問題只是測試比「在程序頂部SET NOCOUNT ON」更難測試嗎?我不知道像Sql Enlight這樣的SQL分析工具是否可以測試這種事情......將它添加到我的SQL格式化工程的長期待辦事項列表中:) – Tao

0

我不知道如何測試客戶端和SQL之間SET NOCOUNT ON,所以我測試了其他SET命令「SET事務隔離級別READ UNCIMMITTED」類似的行爲

我發出的指令從我的連接改變SQL(READ COMMITTED)的默認行爲,並在下一個命令中進行了更改。 當我更改存儲過程內的ISOLATION級別時,它不會更改下一個命令的連接行爲。在存儲過程中

當前的結論,

  1. 更改設置不會更改連接的默認設置。
  2. 通過使用ADOCOnnection發送命令來更改設置會更改默認行爲。

我認爲這是相關的其他SET命令,例如像「SET NOCOUNT ON」

+0

您的第1點是否意味着您並不需要最後設置NOCOUNT OFF,因爲它不會影響全球環境? – funkymushroom

+0

我不確定這是他的意思,但在我的測試中,是的,顯然全局環境不受存儲過程中SET NOCOUNT ON的影響。 – Doug

0
SET NOCOUNT ON; 

這行代碼是SQL用於不返回受影響的查詢的執行數行。如果我們不需要受影響的行數,我們可以使用它,因爲這將有助於節省內存使用量並提高查詢執行的速度。

+1

請注意@@ ROWCOUNT仍然設置。 SET NOCOUNT ON禁止SQL Server發送給客戶端的任何額外響應。請參閱上面接受的答案 – gbn

42
  • 當SET NOCOUNT爲ON時,不會返回count(表示受Transact-SQL語句影響的行數)。 SET NOCOUNT爲OFF時,返回計數。它與任何SELECT,INSERT,UPDATE,DELETE語句一起使用。

  • SET NOCOUNT的設置在執行或運行時設置,而不是在分析時設置。

  • SET NOCOUNT ON提高了存儲過程(SP)的性能。

  • 語法:SET NOCOUNT {ON | OFF} SET NOCOUNT ON的

實施例:

enter image description here

例SET的NOCOUNT OFF:

enter image description here

0

如果(設置沒有計數==關閉)

{ 然後它會保持多條記錄如何影響 數據,從而降低性能 } 其他 { 也不會跟蹤更改的記錄 從而提高perfomace }}

0

我知道這是很老的問題。但只是爲了更新。

使用「SET NOCOUNT ON」的最佳方法是將其作爲第一條語句放在SP中,並在最後一條SELECT語句之前再次將其設置爲OFF。

1

SET NOCOUNT ON; 以上代碼將在DML/DDL命令執行後將由sql server引擎生成的消息停止到前端結果窗口。

爲什麼我們這樣做? 由於SQL服務器引擎需要一些資源來獲取狀態並生成消息,因此它被認爲是Sql服務器引擎的重載。所以我們設置了noncount消息。

相關問題