如何用参数化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.mzph.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;为了能被别的程序调用&…