如何用參數化SQL語句污染你的計劃緩存

你的SQL語句的參數化總是個好想法。使用參數化SQL語句你不會污染你的計劃緩存——錯!!!在這篇文章里我想向你展示下用參數化SQL語句就可以污染你的計劃緩存,這是非常簡單的!

ADO.NET-AddWithValue

ADO.NET是實現像SQL Server關系數據庫數據訪問的.NET框架的組成——有一些嚴重的副作用。不要誤解我——只要你正確使用,ADO.NET一直很棒。你馬上就會看到,它很容易被錯誤使用。我們來看下面實現SQL語句執行的C#代碼。?

 1 for (int i = 1; i <= 100; i++)
 2 {
 3    val += i.ToString();
 4 
 5    cmd = new SqlCommand(
 6       "SELECT * FROM Sales.SalesOrderDetail WHERE CarrierTrackingNumber = @CarrierTrackingNumber", 
 7       cnn);
 8    cmd.Parameters.AddWithValue("@CarrierTrackingNumber", val);
 9    SqlDataReader reader = cmd.ExecuteReader();
10    reader.Close();
11 }

我們是聰明的開發者,因此SQL語句本身被參數化,因為ADO.NET框架是地球上最棒的框架,我們使用System.Data.SqlClient.SqlParameterCollection類的AddWithValue方法來提供實際的參數值。我在WHLIE循環里運行那個SQL語句100次,總用不同長度賦予參數值。在Sales.SalesOrderDetail表里CarrierTrackingNumber列定義為NVARCHAR(25)。因此我們可以在基于我們提供的不同字符長度上有上至25個不同數據類型的參數。現在讓我們檢查下我們SQL語句執行后的計劃緩存。

1 SELECT
2     st.text,
3     cp.*
4 FROM sys.dm_exec_cached_plans cp
5 CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st
6 GO

現在事情變得有點瘋狂:在計劃緩存里我們存儲了100個不同的執行計劃!

?

對于每個可能的數據類型參數都有1個執行計劃——即使當數據類型是NVACHAR(25)AddWithValue方法非常,非常邪惡:基于你提供的參數值派生出數據類型。永遠不要使用它!

ADO.NET – SqlDbType.VarChar

因為從我們的錯誤中我們學到了,現在我們知道ADO.NET的AddWithValue方法的副作用——我們不再用它。現在讓我們重寫我們的C#程序代碼,如下所示定義一個顯示的參數數據類型:?

 1 for (int i = 1; i <= 100; i++)
 2 {
 3    val += i.ToString();
 4 
 5    cmd = new SqlCommand(
 6       "SELECT * FROM Sales.SalesOrderDetail WHERE CarrierTrackingNumber = @CarrierTrackingNumber",
 7       cnn);
 8    cmd.Parameters.Add(new SqlParameter("@CarrierTrackingNumber", SqlDbType.VarChar));
 9    cmd.Parameters["@CarrierTrackingNumber"].Value = val;
10    SqlDataReader reader = cmd.ExecuteReader();
11    reader.Close();
12 }

從代碼里你可以看到,ADO.NET現在不能派生參數數據類型了,因為我們已經指定了SqlDbType.Varchar數據類型。讓我們再次執行這個SQL語句100次并再次檢查下計劃緩存:

?

沒有啥改變。問題還是一樣:在計劃緩存里我們還有100個不一樣的的執行計劃。現在的問題是ADO.NET只強制數據類型(SqlDbType.VarChar),但不是數據類型的"長度"。有100個不同的長度在計劃緩存里你就有100個不同的執行計劃。

如果你在你的ADO.NET代碼里顯式指定參數數據類型,你也要指定它的長度!現在我們來看下一些修正的C#代碼。

 1 for (int i = 1; i <= 100; i++)
 2 {
 3    val += i.ToString();
 4 
 5    cmd = new SqlCommand(
 6       "SELECT * FROM Sales.SalesOrderDetail WHERE CarrierTrackingNumber = @CarrierTrackingNumber",
 7       cnn);
 8    cmd.Parameters.Add(new SqlParameter("@CarrierTrackingNumber", SqlDbType.VarChar, 100));
 9    cmd.Parameters["@CarrierTrackingNumber"].Value = val;
10    SqlDataReader reader = cmd.ExecuteReader();
11    reader.Close();
12 }

這次我也指定了數據類型的長度——這里是100,現在當我們再次執行SQL語句100次時,最后我們在計劃緩存里以1個執行計劃且重用了100次來完美收工。這是從SQL Server角度的最終目標。

?

小結

寓意:ADO.NET是個很棒的數據訪問框架,它提供你有用的功能(例如AddWithValue方法),當從SQL Server角度來說你真的要考慮下你在做什么。當你使用參數化SQL語句時,你要盡量顯式:你必須地冠以參數值的實際數據類型,還有你想要的獲得數據類型長度。

感謝關注!?

參考文章:

https://www.sqlpassion.at/archive/2015/07/20/how-to-pollute-your-plan-cache-with-parameterized-sql-statements/

轉載于:https://www.cnblogs.com/woodytu/p/4751915.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/458982.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/458982.shtml
英文地址,請注明出處:http://en.pswp.cn/news/458982.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

oracle values函數,Oracle文本函數簡介

Oracle文本函數使我們常用的函數&#xff0c;下面就為您介紹幾種Oracle文本函數的用法&#xff0c;供您參考學習&#xff0c;希望可以讓您對Oracle文本函數有更深的認識。(1)UPPER、LOWER和INITCAP這三個函數更改提供給它們的文體的大小寫。select upper(product_name) from pr…

c++ int *p = new int()

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** int *anew int(120); 申請一個整型變量空間&#xff0c;賦初值為120&#xff0c;并…

Ios: 如何保護iOS束文件屬性列表,圖像,SQLite,媒體文件

Ios: 如何保護iOS束文件屬性列表&#xff0c;圖像&#xff0c;SQLite&#xff0c;媒體文件我創建了Hello World示例項目&#xff0c;然後添加data.plist文件到資源文件夾。現在人們可以很容易得到束文件解壓縮。國際音標。有任何的方法來保護data.plist文件保存在iPhone應用程序…

w3wp oracle,w3wp.exe占用CPU超過50%的處理

w3wp.exe占用CPU超過50%的處理1.查看CPU占用高的進程&#xff1a;任務管理器C:\Documents andSettings\Administrator>iisappW3WP.exe PID: 18008 AppPoolId: STATW3WP.exe PID: 8328 AppPoolId: STATW3WP.exe PID: 17868 AppPoolId: JYCV16W3WP.exe PID: 16652 AppPoolId: …

論兩種學習模式

引言 A&#xff1a;你是如何學習的&#xff0c;通過視頻、書籍和實踐結合&#xff1f;B&#xff1a;不是&#xff0c;一般情況是以一個問題為點去畫線和面。 兩種學習模式 按部就班方式獲取知識(通過書、視頻)缺點 信息接收者缺乏深度思考和探索信息發布者的知識體系不一定適合…

啟動mq命令 linux,RocketMQ:Linux下啟動server和broker的命令

目錄QUESTION:RocketMQ&#xff1a;Linux下啟動server和broker的命令?ANSWER:一、啟動mqnamesrv1.1當前執行1.2后臺運行二、啟動mqbroker2.1當前執行2.2后臺運行QUESTION:RocketMQ&#xff1a;Linux下啟動server和broker的命令?ANSWER:一、啟動mqnamesrv1.1當前執行進入rocke…

C++中int *p[4]和 int (*q)[4]的區別

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** C中int *p[4]和 int (*q)[4]的區別 前者是指針數組&#xff0c;后者是指向數組的指針…

Spring筆記③--spring的命名空間

p:命名空間: xmlns:p"http://www.springframework.org/schema/p" 作用:簡化在xml配置bean的屬性 在<bean>中使用p:屬性名來配置 AOP:命名空間: xmlns:aop"http://www.springframework.org/schema/aop" xsi:schemaLocation: http://www.springframewo…

linux不用命令開啟ssh,不用密碼也能ssh登陸Linux?

Linux的一個后門引發對PAM的探究1.1 起因今天在搜索關于Linux下的后門姿勢時&#xff0c;發現一條命令如下&#xff1a;ln -sf /usr/sbin/sshd /tmp/su; /tmp/su -oPort5555;經典后門。直接對sshd建立軟連接&#xff0c;之后用任意密碼登錄即可。ssh rootx.x.x.x -p 5555這個是…

ScrollView常用(暫時用上了的)代理方法

2019獨角獸企業重金招聘Python工程師標準>>> ScrollView常用代理方法: #pragma mark - 滾動結束調用 -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {// 計算 滑動到了第幾頁double page scrollView.contentOffset.x / scrollView.width;self.p…

筆試題目匯總

C常考筆試題:不用if,while,do-while,for,打印出所有大于0小于k的整數.函數原型void printLess(int k); 解法一:遞歸方式(剛想出來) [cpp] view plaincopy #include <iostream> using namespace std; void printLess(int k) { switch(--k) { case 0:…

Android ListView性能優化實例講解

前言&#xff1a; 對于ListView&#xff0c;大家絕對都不會陌生&#xff0c;只要是做過Android開發的人&#xff0c;哪有不用ListView的呢&#xff1f; 只要是用過ListView的人&#xff0c;哪有不關心對它性能優化的呢&#xff1f; 關于如何對ListView進行性能優化&#xff0c;…

Bzoj 3289: Mato的文件管理 莫隊,樹狀數組,逆序對,離散化,分塊

3289: Mato的文件管理 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 1539 Solved: 665[Submit][Status][Discuss]Description Mato同學從各路神犇以各種方式&#xff08;你們懂的&#xff09;收集了許多資料&#xff0c;這些資料一共有n份&#xff0c;每份有一個大小和一…

linux頭文件 庫,Linux操作系統的頭文件和庫文件搜索路徑

一、 頭文件1 “”中的頭文件&#xff0c;在源文件當前目錄查找2 -I 中指定目錄 -I可以在CFLAG中指定3 gcc的環境變量 C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH4 編譯器預設路徑、內定目錄&#xff1a;/usr/include/usr/local/include/usr/lib/gcc-lib/i386-lin…

vs2010創建和使用動態鏈接庫(dll)

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** 本文將創建一個簡單的動態鏈接庫&#xff0c;并編寫一個應用臺控制程序使用該動態鏈接…

通用二進制

通用二進制 通用二進制&#xff08;Universal binary&#xff09;是蘋果電腦公司提出的一種程序代碼&#xff0c;使程序能以本地程序的形式運行在使用PowerPC或者英特爾微處理器&#xff08;x86&#xff09;的麥金塔電腦上&#xff0c;在同一個程序包中同時為兩種架構提供最理想…

Python~win32com~Excel

import win32com.client#wwin32com.client.Dispatch("Word.Application") #w.Visible1owin32com.client.Dispatch("Excel.Application") o.Visible1 o.Workbooks.Add() o.Cells(1,1).Value"Hello"轉載于:https://www.cnblogs.com/lynclynn/p/530…

linux顯示光盤命令行,使用wodim在命令行下燒錄光盤

使用wodim在命令行下燒錄光盤發布時間:2009-02-27 16:23:11來源:紅聯作者:zhania作者&#xff1a;linuxtoy出自http://linuxtoy.org/archives/burning-cd-with-wodim.html我們以前介紹的 Linux 光盤燒錄工具多為圖形化的程序&#xff0c;今天來看看如何使用 wodim 在命令行下燒…

Android(java)學習筆記144:網絡圖片瀏覽器的實現(ANR)

1.我們在Android下&#xff0c;實現使用http協議進行網絡通信&#xff0c;請求網絡數據。這里是獲取網絡上的圖片信息&#xff0c;讓它可以顯示在手機上&#xff1b; 但是我們這個手機連接網絡是很費時間&#xff0c;如果我們在主線程&#xff08;UI線程&#xff09;中寫這個網…

DLL導出函數名稱改編的解決方法

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** 1.DLL編譯后導出函數名稱改變 在編寫一個DLL后&#xff0c;為了能被別的程序調用&…