參數化查詢的另一個作用


關於參數化暫時有發現有兩個作用:

  1. 防止SQL注入.
  2. 執行計划的重用

 

這里我主要講的是執行計划的重用這塊.  

 

我們項目中寫的SQLSQL SERVER中都會先生成一個唯一的hash值,然后根據這個hash值去緩存里面匹配對應的執行計划.

如果執行計划.不存在,則開始走生成執行計划的模塊(注:這個模塊是很耗效能的,以至於連微軟都要把這個執行計划緩存)

 

所以我們在寫SQL的過程中,如果有一個字符發生變動(即使是一個空格),都會導致hash的變動,進而會重新編譯該SQL對應的執行計划

例如: 

 

 

 

上面這個圖兩者的sql作用是一樣的,但是因為第1個SQL多了個空格,導致SQL Server重新編譯了該sql語句

 

而我們日常開發中,有關客戶端傳遞過來的值;,我們大部分都會用參數化,而項目里面直接寫的,可能就會直接聲明了, 這樣就會導致下面這種情況→_→

直接聲明:

  

在換個其他值測試:

再次執行,且觀察執行計划可得知

可以得知我們手寫的SQL是執行的SQL自動生成的執行計划,而非我們自己手寫的執行計划。而使用次數作用到了手寫的SQL上面。 

 

另一種方式,我們改用參數化

 

 換其他值測試:

 

 

上述的測試中:一個簡單的非參數化的SQL就已經占用了16KB的內存,如果是多表聯合查詢或者復雜性的查詢,會造成多少內存的浪費,因為原本用一個執行計划就搞定的,現在卻多出了N個。

如果我們項目中大量的SQL都將固定的值寫在sql里面,我們認為會只用一個SQL執行計划,實際上是SQL Server將我們的每個sql都編譯了一個執行計划,在一定程度上增加了對性能和內存的消耗。

所以我們項目中如果是固定的值,也要提取到參數化里面,這樣可以共享一個執行計划,節省性能以及內存的消耗。  

 

-------------華麗的分界線------------------

 

擴展: 上述的測試中,用參數化執行SQL的方式,我遇到過這種情況, 即如下:

 

使用了參數化卻還是生成了兩個執行計划,通過分析可發現是因為SQL Parameter沒有傳入長度所致, 調整輸入長度后 測試如下: 

 

進一步可得知,如果參數化的時候不指定字段長度的話(我這里指定30是因為Address表中的City字段類型是:nvarchar(30)),也會在一定程度上造成多余執行計划的增長,進而造成內存的浪費。

 

結語:

 

當完全參數化的可能還會出現參數嗅探的問題,所以在使用的時候,還得具體情況具體分析。

 

目前有個問題想請教下,就是當非參數化的時候,SQL SERVER自動生成的執行計划是做什么用的?

>>這個部分感謝答復我問題的@MSSQL123大神,他解答了我對這個部分的疑惑,非常感謝:)

 

=================結束的分割線=====================

 

上面主要用的SQL如下:

 

清空執行計划:

DBCC FreeProcCache

查詢上面結果的SQL

SELECT 

cp.usecounts as '使用次數' ,

cp.cacheobjtype as '緩存類型',

cp.objtype as '對象類型',

st.text as 'TSQL',

qp.query_plan as '執行計划',

cp.size_in_bytes as '執行計划占用空間(byte)'

FROM

sys.dm_exec_cached_plans cp

cross apply sys.dm_exec_sql_text(plan_handle) st

cross apply sys.dm_exec_query_plan(plan_handle) qp

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM