2011-12-19 71 views
11

事實上,如果我從我的應用程序調用存儲過程,我需要連接到我的數據庫。爲什麼執行存儲過程比腳本中的SQL查詢更快?

那麼,爲什麼調用「存儲過程」應該比「傳遞SQL查詢」字符串要執行更快?

+8

真的是沒有太多的存儲過程的速度優勢了,這些天。正確的參數化查詢將與存儲過程一樣高效。單憑這一點不是使用存儲過程 – 2011-12-19 09:51:41

回答

40

SQL服務器基本上會經過以下步驟執行任何查詢(存儲過程調用或即席SQL語句):

1)語法檢查查詢
2)如果是好的 - 它會檢查計劃緩存以查看它是否已經有針對該查詢的執行計劃
3)如果有執行計劃 - 該計劃被(重新)使用並且執行查詢
4)如果還沒有計劃,執行計劃確定
5)該計劃存儲在計劃緩存中供以後重新使用
6)執行查詢

的一點是:即席SQL和存儲過程是treatly 沒有區別

如果一個特設的SQL查詢是否正確使用參數 - 因爲它應該無論如何,以防止SQL注入攻擊 - 它的性能並沒有什麼不同,最肯定不超過執行一個存儲過程更糟

存儲過程有其他的好處(無需授予用戶直接訪問表,例如),但在性能方面,採用適當的參數化即席SQL查詢是一樣高效如使用存儲過程。

更新:使用存儲過程非參數化查詢是更好的原因主要有兩個:

  • ,因爲每一個非參數化查詢是新的,不同的查詢到SQL Server,它必須經歷確定每個查詢的執行計劃的所有步驟(從而浪費時間 - 並且浪費計劃緩存空間,因爲將執行計劃存儲到計劃緩存中並不真的有助於最終,因爲該特定查詢可能會而不是再次執行)

  • 非參數化查詢是在SQL注入攻擊的風險,應不惜一切代價

+0

P.S. SP存儲/緩存...但例如,如果我有一個「where」子句,我從客戶端傳遞一個自定義值,它應該與該輸入/條件編譯;所以每個參數都有專用的SP? – markzzz 2011-12-19 10:19:24

+1

@markzzz:不,在這種情況下,我會向存儲過程的定義(要從調用者傳遞)添加一個參數,並在存儲過程的「主體」中使用該參數。這樣,再次,你有一個**存儲proc主體,**一個**(緩存)的執行計劃,你可以用任何可能的值調用它。 – 2011-12-19 11:39:46

+0

@marc_s:非參數化查詢如何處於sql注入風險中,因爲非參數化查詢永遠不會接受任何參數。讓我知道我是否有錯 – 2014-03-14 07:38:19

2

存儲過程被編譯和緩存。但是,SQL語句將與現有的執行計劃進行比較,如果使用了匹配項,則會使某些優勢無效。

多次執行後的實際性能差異是多少?

+0

的好理由?這是什麼意思?結果被緩存或只是SQL查詢? – markzzz 2011-12-19 09:48:37

+1

我喜歡得到真實的答案。 – NimChimpsky 2011-12-19 09:55:07

+0

@marc_s我還在寫答案。我想我應該知道規則。叢林法則等等。而且,一個sql查詢只會在第一次運行後執行計劃存在時纔會與sproc相同,而不像正在創建的sproc。 – NimChimpsky 2011-12-19 10:01:30

5

因爲每次將查詢字符串傳遞給SQL Server時,代碼都必須進行編譯等,因此存儲過程已經編譯並準備在服務器上運行。

此外,您通過網絡發送的數據較少,儘管這通常影響最小。

編輯: 作爲備註存儲過程有其他好處。

1)安全性 - 因爲實際的查詢存儲你不通過,這意味着任何人攔截網絡流量不會獲得任何洞察到你的表結構的網絡傳輸該服務器上。另外一個精心設計的SP可以防止注入攻擊。

2)代碼分離 - ,你把你的數據庫的代碼在你的數據庫和應用程序中的應用程序代碼中,很少有交叉,我發現這使得bug修復要好很多。

3)可維護性和代碼重用,您可以重複使用一個過程多次而不必複製粘貼查詢,如果您想更新查詢,您只需要在一個地方更新它。

4)減少網絡流量。如上所述,這對大多數人來說可能不是問題,但對於大型應用程序,通過切換到使用存儲過程,可以顯着減少通過網絡傳輸的數據量。

+3

任何存儲過程必須首先進行分析,確定執行計劃等才能被緩存。任何參數化查詢都經歷了相同的過程,因此與存儲過程真的具有相同的性能優勢 – 2011-12-19 10:00:54

+0

多數民衆贊成在有趣的感謝,我一直認爲這個過程實際上是優化存儲過程。 – Purplegoldfish 2011-12-19 10:17:01

+1

但是執行計劃不會爲存儲過程而無限期地存儲,並且每次都會產生臨時查詢?事情可能已經發生了變化,但這是我以前相信的。這可能意味着使用存儲的特效可獲得巨大的性能提升雖然如果我沒有正確記住,這取決於你在存儲過程中做了什麼,如果它很複雜,執行計劃可能在每次調用時都會重新生成。任何意見? – infocyde 2012-12-05 23:55:28

0

與標準SQL語句不同,存儲過程由數據庫服務器編譯和優化。此優化涉及使用有關存儲過程在執行時所需的特定數據庫結構的信息。存儲執行信息(執行計劃)的這個過程是極大的節省時間,特別是如果存儲過程被多次調用。

速度也因存儲過程完全在數據庫服務器上運行這一事實而得到改進 - 不需要通過網絡傳遞大量SQL代碼。對於一個簡單的SELECT語句,可能不會有很大的不同,但在我們進行一系列的循環和計算的情況下,它可以有顯著的效果。

+4

這不完全正確;正確的參數化查詢就像編譯和存儲在​​SQL Server的計劃緩存中一樣 - 在執行速度/性能方面實際上沒有太多(如果有的話)差異。 – 2011-12-19 09:50:11

3

你的語句存儲過程是比SQL查詢更快避免只是部分正確。解釋:大多數這些答案已經解釋了使用存儲過程生成並緩存查詢計劃。因此,如果再次調用存儲過程,SQL引擎將首先搜索其查詢計劃列表,如果找到匹配項,它將使用優化計劃。

傳遞正常查詢不允許使用此優勢,因爲SQL引擎不知道該期待什麼,因此無法爲您的查詢找到匹配項。它從頭開始創建一個計劃,然後呈現結果。

好消息:您可以使用參數化查詢(SQL中的一項新功能)爲查詢啓用計劃緩存。這使您能夠爲您的查詢生成計劃,並且在您的情況下可以非常有效,因爲您從代碼傳遞的大多數查詢都保持不變,除了Where子句中的大部分變量。還有一個設置可以強制所有查詢的參數化。搜索這個主題的MSDN,應該幫助你決定什麼是最好的。

然而,此說,存儲過程仍然與DB從您的應用程序進行交互,因爲它提供了一個額外的安全層的好方法。

希望這有幫助!

0
  1. 存儲過程有時運行得快一點,因爲或使用RPC調用時可能
  2. SP運行對於必須重新編譯的查詢速度更快 - 爲前。 - 使用臨時表的作品在中間
3

另一個問題是在什麼地方看,比較web服務器和這個 -

EXEC的someproc @ VAR1 =「嗒嗒」數據庫服務器之間的網絡流量, @ VAR2 = '嗒嗒',@ VAR3 = '嗒嗒'

爲了這個 -

選擇場,場2,字段3,字段4,字段5,字段6 .... field30 上table2.field12 =表1表1加盟.field12 where blah blah blah 和table1.field3 = @ var1的和table2.field44 = @ var2的和(table1.field1爲空或table1.field1 = @ VAR3 .......

查看不同?對我們99%的人來說,這可能並不重要,但是對於你們中的一些人來說,編寫高性能的應用程序可能會這樣,儘管可能有一些緩存或其他處理方式。

我想有很多人誰聲稱有即席查詢和存儲過程沒有什麼區別,一般使用表作爲對象存儲爲他們所使用的任何ORM,這是好的。仍然有很多大量的數據驅動的企業應用程序,無論是正確的還是錯誤的,都有超過1000行的存儲過程。你最終可能會在他們身上工作。此外,對於那些你們誰可能不得不在一段時間每一次生產的變化和需要繞過正規程序是很多比生產編譯代碼更容易做到這一點在數據庫中。改變proc ...完成。牛仔,可怕,邪惡,發生。是的,我知道在你的許多想法中這樣做是不可饒恕的罪行,剪切斜坡的跡象......但它發生了。只是要考慮一下。

我知道最新的工具通常使用存儲的特效痛苦在後面,如果你期望得到很好地爲您生成所有的實體做出,但存儲的特效依然有自己的位置的時候。

+1

假設您的網格一次顯示20條記錄,但查詢返回20,000條匹配記錄。使用實體框架,您可以在代碼中進行分頁,以便將20,000條記錄中的數據剪切爲20條記錄,並將其傳送至瀏覽器。但是20,000個記錄仍然從數據庫服務器發送到Web服務器。通過存儲過程,您可以在proc中處理分頁邏輯,因此20條記錄從數據庫服務器發送到Web服務器,然後發送到客戶端。數據庫服務器和Web服務器之間的流量較少。還有別的想法。 – infocyde 2015-02-03 23:07:38

+0

[冗餘],已刪除。 – infocyde 2015-02-03 23:08:20

+0

對於Entity Framework來說,這種情況並不那麼正確,它似乎只處理了20個需要的記錄,而沒有數據庫服務器吮吸20,000個記錄,就像我們的例子中那樣。儘管Web服務器和數據庫服務器之間的數據流量仍然是一個問題。存儲的特效減少了。 – infocyde 2018-01-24 23:16:13

相關問題