是否会成为问题——Linq to Sql的执行可能无法复用查询计划

查询计划

Sql Server在执行一条查询语句之前都对对它进行“编译”并生成“查询计划”,查询计划告诉Sql Server的查询引擎应该用什么方式进行工作。Sql Server会根据当前它可以收集到的各种信息(例如内存大小,索引的统计等等)把一条查询语句编译成它认为“最优”的查询计划。很显然,得到这样一个查询计划需要消耗CPU资源,而大部分的查询语句每次经过编译所得到的查询计划往往是相同的,因此除非指定了RECOMPILE选项,Sql Server在执行查询语句时,会对查询计划进行缓存——也就是说,如果是相同的查询语句,Sql Server只会对它进行一次编译操作,然后在每次执行时对查询计划进行复用。查询计划如果无法复用,则会在相当程度上降低数据库性能——因为过多的CPU被消耗在查询语句的编译上。各种提及数据库查询优化的资料上大都会提到这一点,我们往往通过查看性能计数器的某些统计,或者Sql Server系统表中的一些记录,就可以判定您的数据库应用是否出现了这个问题。

对于存储过程来说,复用查询计划是轻而易举的。不过对于那些喜欢在程序代码中拼接Sql字符串的朋友来说,日子就有些不好过了。Sql Server是根据您传入的Sql语句来缓存查询计划的,如果您“强行”拼接了Sql字符串并交给Sql Server执行,那么查询计划被复用的可能性微乎其微。因此,我们绝对应该杜绝拼接字符串的行为,因为这不仅仅造成了传统的Sql注入!而那些习惯相对较好的朋友,则会使用带参数的Sql语句,在交给Sql Server执行时就可能复用查询计划。因为和调用存储过程相比,发送带参数的Sql语句只是将使用了sp_executesql命令而已,每次执行的查询语句还是相同的。

问题何在?

对于复用查询计划的问题,在上文中我说了这么一句话:“……使用带参数的Sql语句,在交给Sql Server执行时就可能复用查询计划……”。我为什么要说“可能”?因为即时使用带参数的Sql语句,在某些情况下我们还是无法对查询计划进行复用。这是怎么一回事儿呢?我们还是直接从Linq to Sql来产生Sql语句,然后观察Sql Server的行为吧。

请看以下的代码(示例所操作的数据表与《在Linq to Sql中管理并发更新时的冲突(2):引发更新冲突》一文相同):

LinqToSqlDemoDataContext dataContext = new LinqToSqlDemoDataContext();
dataContext.Log = Console.Out;

Video video1 = dataContext.Videos.SingleOrDefault(
    v => v.Introduction == "Hello");
Video video2 = dataContext.Videos.SingleOrDefault(
    v => v.Introduction == "Hello World");

Console.ReadLine();

还是查看输出:

SELECT [t0].[VideoID], [t0].[Introduction], [t0].[SiteID]
FROM [dbo].[Video] AS [t0]
WHERE [t0].[Introduction] = @p0
-- @p0: Input NVarChar (Size = 5; Prec = 0; Scale = 0) [Hello]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21004.1

SELECT [t0].[VideoID], [t0].[Introduction], [t0].[SiteID]
FROM [dbo].[Video] AS [t0]
WHERE [t0].[Introduction] = @p0
-- @p0: Input NVarChar (Size = 11; Prec = 0; Scale = 0) [Hello World]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21004.1 

两局Sql语句完全相同,按我们刚才的说法,Sql Server应该缓存了查询计划。但是我们通过查看sys.syscacheobjects的相关数据可以看出,事情并非如同我们想象的那样:

SELECT cacheobjtype, sql FROM sys.syscacheobjects;
DBCC freeproccache;

linq2sql-cannot-cache-compiled-plan-1.jpg

请注意上图中被选中的两条记录,它表明了Sql Server并没有缓存执行计划。

为什么?这两次执行究竟有什么区别?通过Linq to Sql很容易看出,两次执行所用到的参数不同。更进一步,如果对比Linq to Sql输出的缓存以及sys.syscacheobjects视图中的记录,就会发现:其实仅仅是参数的尺寸不同。

没错,就是这个原因。在使用ADO.NET时,如果SqlParameter的Type是nvarchar,并且没有指定Size属性,则可能就会因为具体参数的尺寸不同而造成查询计划无法复用的结果。这一点,很多人都忽视了。

优化方案

在使用ADO.NET进行开发时,该问题其实很容易解决。我们只要指定SqlParameter的Size属性即可。由于每次指定了一个固定的参数尺寸,Sql Server就能够复用查询计划了。

不过我们现在在使用Linq to Sql,又该怎么做呢?嗯,我们可以为XXXXDataContext重写(override)SubmitChanges方法,在其中获得需要执行的SqlCommand对象(具体方法请参考《在Linq to Sql中管理并发更新时的冲突(1):预备知识》一文),获得其中的SqlParameter参数,并设定它们的Size属性。我们可以使用Custom Attribute来标注应该为哪个属性设置什么样的Size,如果再结合AOP,哈哈……

等等,先别想那么远。即使得到了SqlCommand对象,它所生成的Sql语句是以@p0、@p1作为参数名,您知道该修改哪个SqlParameter对象吗?再者,SubmitChanges方法只是提交我们做出的修改,但是在一般的系统中,查询操作的次数和性能消耗大大超过修改操作,而重写了SubmitChangeds方法又不能影响我们的优化操作……

因此,我想在这里说的是:这个问题我们没法进行优化。

不过我们还是幸运的,因为我根据我的经验,似乎在查询条件中使用长度不等的字符串作为参数的情况并不多见。不是么?

转载于:https://www.cnblogs.com/JeffreyZhao/archive/2007/11/21/linq-to-sql-cannot-cache-compiled-plan.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/381691.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第七届山东省Acm程序设计竞赛赛后总结

其实这次相对来说是比较轻松的,经过差不多2年的磨合,大家的默契度已经配合的足够熟练,而对于考场的压力和紧张感,相比去年前几次要放松许多,说来实在奇怪,去年我们嚷嚷着要拿XXX,到最后一无所获…

再别康桥

轻轻的我走了,正如我轻轻的来;我轻轻的招手,作别西天的云彩。那河畔的金柳是夕阳中的新娘波光里的艳影,在我的心头荡漾。软泥上的青荇,油油的在水底招摇;在康河的柔波里,我甘心做一条水草那树荫…

Java在ACM中的应用

Chapter I. Java的优缺点各种书上都有,这里只说说用Java做ACM-ICPC的特点: (1) 最明显的好处是,学会Java,可以参加Java Challenge :) (2) 对于熟悉C/C的程序员来说,Java 并不难学,找本书,一两…

Lucas定理及组合数取模

首先给出这个Lucas定理: A、B是非负整数,p是质数。AB写成p进制:Aa[n]a[n-1]...a[0],Bb[n]b[n-1]...b[0]。 则组合数C(A,B)与C(a[n],b[n])*C(a[n-1],b[n-1])*...*C(a[0],b[0]) modp同余 即:Lucas(n,m,p)c(n%p,m%p)*Luc…

系统优化设置-之二

5、关掉不必要的服务 单击“开始”→“设置”→“控制面板”。双击“管理工具”→“服务”,打开后将看到服务列表,有些服务已经启动,有些则没有。右键单击要配置的服务,然后单击“属性”。在“常规”选项卡上选择“自动”、“手动…

CCPC网络赛前一周的充电计划

CCPC大概还有一周左右的时间,在这一周内,要补充一些数学内容,避免出现像去年学长们一样出现的情况,不能出现在碰到相关题目的时候面面相嘘不知所以然。 所以这几天的计划大体是: 1. Lucas定理 : 题库 2. 中国剩余定…

解决手机死机之锦囊妙计

引言 不久前买的586W我的是T版的英文说明书,只见说明书中介绍说如果死机的话只须拔掉电池重新安回即可.当时我就郁闷了拔电池呀?多伤机器呀?有一次下载了个JAVA游戏,刚运行就死机了(游戏BUG).于是我便想到了说明书中说道的拔电池.思前想后还是没拔,怕伤了机器;我抱着试试…

hdu 4349——Xiao Ming's Hope

题意:给定n,让求c(n,0),c(n,1)……c(n,n)中有多少奇数。 思路:本题为Lucas定理推导题,我们分析一下 C(n,m)%2,那么由lucas定理,我们可以写 成二进制的形式观察,比如 n1001101,m是从000000到10…

介绍及安装

不知读者是否听说过“宠物大战”?大意为Sun公司为帮助开发人员和架构师使用J2EE技术,发布了一个在线宠物商店Sun Java Pet Store。而微软公司则利用.NET技术也发布了一个实现同样功能的PetShop,并且在代码数量、性能等各方面对二者进行了比较…

hdu5446——Unknown Treasure

题意:给定n和m,求c(n,m)%(∏ p)的值,相当于lucas定理的一个推广,在p不是素数的情况下的一个解决方法。 思路: 首先对于c(n,m)%p[i]来讲,是一个lucas的裸题,那么对于c(n,m)%(∏ p)划分成lucas子…

自定函数获取datagrid,datalist,rpeater控件中header,footer栏中控件

在论坛上看到很多关于datagrid,gridview,datalist,rpeater提取header,footer中控件的问题,整理了一下.供大家分享下面我以DataGrid为便进行说明.footer栏又称页脚栏,在很多时候我们可以在该栏放页码及相当的功能键.但是最后在获得这些控件引用的时候就会有点麻烦,由于footer(页…

如何做好一名软件实施人员 (转载)

通过一年的软件实施,使我深深的感觉到,软件实施,其实并不是一件很容易的事,也许可算是一项挑战,很需要“明知山有虎,偏向虎山行”的信心和勇气。为什么这样说呢? 因为,软件实施可以说…

hdu 5802——Windows 10

题意:给定两个音量,需要从l调到r,每次只能向上一下或者向下(1,2,4,2^n)下(连续向下的情况下),每次可以停歇或向上来打断向下的连续性,…

20160807_第一周周报

写在前面 以后每周周日要进行一次周报,内容长短不限,为这一周的知识点和心态方面的总结,还有就是对未来的相关规划和调节!知识点方面 在知识点方面进度不是太大,打的还是一般化的套路,在这个周的前几天的…

微软认证题库

微软认证题库 70-320XML Web Service开发for C#模拟题实用软件工程方法题库MCP 70-300:基于.NET的需求分析和解决方案设计认证题库三个认证题库点击直接下载posted on 2007-12-12 22:32 当当 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/hyzhi/a…

hdu 5783——Divide the Sequence

题意及思路: 求一个序列的分段个数,使得每一段的前缀和为0,如果正向思维,那么解法是从前往后遍历,每遇到一个负数就向前遍历直到>0(这样贪心保证了序列尽可能多),但是这样最坏的情况是n^2的…

IE7快捷键

快捷方式 常规 打开或关闭全屏模式F11移动选择网页上的地址栏、“刷新”按钮、搜索框和项目Tab查找页面上的字词或短语CtrlF在新窗口中打开当前网页CtrlN打印页面CtrlP选择页面上的所有项目CtrlA放大Ctrl加号缩小Ctrl减号缩放到 100%Ctrl0导航快捷方式 转至主页 AltHome后退Alt…

BestCoder Round #86 1002 HDU 5805 ——NanoApe Loves Sequence

题意 给定一个数列,随机从该数列里删除一个数,求该数列的的相邻之间的绝对值的最大值的和。 思路 两个数列来分别维护i位前面的相邻的绝对值的最大以及i后面的最大,枚举每一个可能删除的数,然后分别从左右和要删除的这个空档里…

BestCoder Round #86 1003 HDU 5806——NanoApe Loves Sequence Ⅱ

题意: 给定一个序列,问在这个序列里有多少区间第k的的数>m 思路: 在比赛的时候是多想了,开始像区间第k大的问题,赛后想想实在是偏了。 正确的解法是枚举起点然后用尺取法维护一段区间,直到找到k个数…

Could not load the assembly 'DotNetNuke.Authentication.LiveID'. Make sure that it is compiled before

今天发生一个莫名的错误:Could not load the assembly DotNetNuke.Authentication.LiveID. Make sure that it is compiled before,在网上找了下有如下的解释: My understanding and perhaps a core member would be willing to correct me i…