儲存過程 引數化SQL 拼SQL 效率VS實用VS

2021-06-04 23:24:11 字數 2471 閱讀 9681

先站在應用程式的角度說說它們的不同。

1、 直接拼sql

就像大家了解的那樣,直接拼sql帶來了sql注入攻擊,帶來了拼時些許的效能損失,但是拼不用新增sqlparameter,會少寫很多**——很多人喜歡直接拼,也許就因為這點。這種做法會把你拼好的sql原樣直接傳送到db伺服器去執行。(注意類似」exec yourproc 『param1』, 12」的語句不在此範疇,這是呼叫儲存過程的一種方式)

2、 引數化sql

所謂的「引數化sql」就是在應用程式側設定sqlcommand.commandtext的時候使用引數(如:@param1),然後通過sqlcommand.parameters.add來設定這些引數的值。這種做法會把你準備好的命令通過sp_executesql系統儲存過程來執行。通過引數化sql,和直接拼sql相比,最直接的好處就是沒有sql注入攻擊了。

3、 呼叫儲存過程

直接呼叫儲存過程其實和引數化sql非常相似。唯一的本質不同在於你傳送到db伺服器的指令不再是sp_executesql,而是直接的儲存過程呼叫而已。

很多人非常非常厭惡在應用程式中使用儲存過程,而寧願使用拼sql或者引數化sql,理由是它們提供了更好的靈活性。

現在做設計,一般都是從上到下來,重心都在業務邏輯上。傳說中的領域模型設計完,測試用例都通過之後,才會考慮資料持久化方式。資料持久化是系統的一部分,但絕對不是最重要的部分,設計應該圍繞業務邏輯開展,持久化應該僅僅是個附件。至少,高層應用應該盡可能的不關心處於最底層的物理儲存結構(如:表)和資料持久、反持久方式(是拼sql還是儲存過程),所以用不用儲存過程根本不重要。很多人害怕儲存過程,其實是害怕儲存過程中包括業務邏輯——真實情況是,如果儲存過程中包含了業務邏輯,那一定最初需求分析不夠導致用例提取不足,導致測試用例覆蓋不夠,導致領域模型設計不充分,要不就是偷懶。

站在db角度討論它們的不同,主要從cpu、記憶體方面來考慮,其他諸如安全性,msdn上都有,google也能拿到一堆資料,不再贅述。

首先是查詢計畫。

sql編譯完一條sql之後,會把它快取起來(可以通過sys.syscacheobjects系統檢視檢視),以後再有相同的查詢過來(注意sys.syscacheobjects檢視中的sql欄位,和它儲存的東西完全一樣才能稱為「相同的查詢」),會直接使用快取,而不再重新編譯。

ø 儲存過程,只編譯一遍(如果沒有指定with recompile選項的話,如果指定了,根本就不會生成計畫快取)。

ø 引數化sql,和儲存過程基本一樣,只要是相同的查詢,也都是只編譯一次,以後重用(當然,指定了option(recompile)的除外)。這裡不得不提.net sqlclient元件的乙個齷齪:如果你的引數中包含varchar或者char型別的引數,你在parameters.add的時候又沒有指定長度,它都會根據你實際傳入的字串長度(假設是n)給你重新定義成nvarchar(n)。如:select * from mytable where col1 = @p1,你設定@p1為』123456』,實際傳到sql這邊的命令是:exec sp_executesql n'select * from mytable where col1 = @p1',n'@p1 nvarchar(6)',@p1=n'123456'。這樣,系統快取中實際儲存的sql是:(@p1 nvarchar(6))select * from mytable where col1 = @p1。看到了吧?如果你的輸入引數變動比較多,那麼看起來同樣的一條語句,會被編譯很多次,在快取中儲存很多份。cpu和記憶體都浪費了。這也是在《寫有效率的sql查詢iv》中建議的使用最強型別引數匹配的原因之一。

ø 拼sql。到這裡不說大家也猜的出來,拼sql要浪費大量的cpu進行編譯,浪費大量快取空間來儲存只用一次的查詢計畫

伺服器的物理記憶體有限,sqlserver的快取空間也有限。有限的空間應該被充分利用。通過效能計數器sql server:buffer manager\buffer cache hit ratio來觀察快取命中率。如果它小於百分之90,你就得研究研究了。關注一把諸如sys.dm_os_memory_cache_counters、sys.dm_os_memory_cache_entries、sys.dm_os_memory_cache_hash_tables、sys.syscacheobjects等檢視,基本可以確定問題出在哪兒。

cpu方面需要關注三個效能計數器:sqlserver:sql statistics\batch requests/sec、sqlserver:sql statistics\ sqlcompilations/sec、sqlserver:sql statistics\ sql re-compilations/sec。如果compilations數目超過batch請求數目的百分之10,或者recompilations數目超過compilations數目的百分之10,那基本可以說明cpu消耗了太多在編譯查詢計畫上面

sql儲存過程in 多個引數

首先要建立乙個擷取字串的函式,新建乙個查詢,把下面 複製進去執行。函式sqlitin的第乙個引數是儲存過程要in的字串,第二個引數是分隔符 create function splitin c varchar 200 split varchar 2 returns t table col varcha...

SQL 儲存過程 傳入陣列引數

今天在做統計資料的時候,傳入陣列導致資料不顯示。解決方式和大家分享一下 引數 companyname 北京,天津,上海 declare pointerprev int declare pointercurr int declare tname nvarchar 100 set pointerprev...

SQL儲存過程

什麼是儲存過程呢?定義 將常用的或很複雜的工作,預先用sql語句寫好並用乙個指定的名稱儲存起來,那麼以後要叫資料庫提供與已定義好的儲存過程的功能相同的服務時,只需呼叫execute,即可自動完成命令。講到這裡,可能有人要問 這麼說儲存過程就是一堆sql語句而已啊?microsoft公司為什麼還要新增...