问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

参数化的sql语句如何应付多变的update

发布网友 发布时间:2022-04-08 08:31

我来回答

2个回答

懂视网 时间:2022-04-08 12:52

在这篇文章里我想向你展示下用参数化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语句时,你要尽量显式:你必须地冠以参数值的实际数据类型,还有你想要的获得数据类型长度。

感谢关注! 

如何用参数化SQL语句污染你的计划缓存

标签:

热心网友 时间:2022-04-08 10:00

string str ="1,2,3,4,5";
string sql="delete from stuinfo where id in ('"+str+"')"
如果是in里面的条件,可以组合成一个字符串。
如果id是字符类型
string str ="'1','2','3','4','5'";
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
怎么用物流寄物流 “祥光彻太清”的出处是哪里 "奉嗣王祗见厥祖,侯甸群后咸在,百官总已以听冢宰"什么意思 ...无逸》:“周公曰:呜呼!嗣王其监于兹!”这里所谓“嗣王”指的是... “宣入嗣王封”的出处是哪里 “词云秦嗣王”的出处是哪里 “家天下兮繇姒氏”的出处是哪里 sktal00是华为什么型号 figureout与workout的区别是什么 figureout什么意思 荣耀50se手机支持耳返功能吗? 荣耀magic3支持耳返吗? 荣耀60支持耳返嘛? 2021哪种型号手机有耳返2021年有哪些手机带有耳返功能的,求介绍 嚣张,这首歌怎么唱好听呢? 嚣张的意思是什么 嚣张的意思是什么? 歌曲《嚣张》的报幕词怎么写? 男朋友邀你听嚣张这首歌是怎么了? 断联三天后,男友在朋友圈发嚣张这首歌,啥意思? 有人能解释卢凯彤的《嚣张》吗? 《嚣张》有刀吗 嚣张歌词。没纠缠是你的理由太假是什么意思? 女朋友让我听嚣张这首歌是什么意思? 嚣张那首歌是在分手后还想着那个人吗? 李俊旭的《嚣张》 歌词 王卡骑手版首月资费是什么 卢凯彤的《嚣张》 歌词 嚣张原唱 王卡骑手版是什么 红米k30支持耳返吗? 荣耀play5T手机属于安卓5.0以上系统吗?能否有全民K歌耳返功能? 那些手机耳返效果比较好啊? VIVO Z5和IQOO NEO 两款手机支持实时耳返吗? 不懂就问:百度地图是怎么知道实时路况的 百度地图和高德地图的实时路况数据分别来自哪里 实时路况GPS是怎样获得实时路况的?有这种手机吗? 百度和高德地图的实时路况是怎样实现的? 华为平板锁屏密码忘了怎么解锁?试过刷新 但是每次都显示更新失败 钱塘江潮水是海水吗? 钱塘江大潮是怎么回事。为什么八月十八会比平时的潮水大。他是海水倒灌么? 钱塘江大潮的潮水是咸水还是淡水? 揭露和揭发的区别求大神帮助 钱塘江海潮形成的原因? 序列号是否只能用一次 ~ ~~急需 “揭晓”这个词的结构类型? 钱塘潮是如何发生的? 买一个正版的软件,序列号一般能用几次? 信号差怎么回事 正版的游戏序列号是不是只能用一次..?