为什么对于不同的项目,相同的Linq-to-SQL查询在数据库服务器上消耗更多的CPU时间
本文关键字:服务器 时间 CPU 数据库 查询 项目 于不同 为什么 Linq-to-SQL | 更新日期: 2023-09-27 18:20:50
我有一个遗留.Net 4项目(名称为"a"),它使用Linq to SQL查询数据库我有另一个.Net 4项目(名称为"B"),它具有类似但不同的代码,可以查询与"A"相同的数据库。
两个项目:
- 是C#项目{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- 使用相同的程序集(版本v4.0.30119,相同的文件夹)
- System.dll
- System.Data.dll
- System.Data.Linq.dll
自动生成的DataContext对每个项目都是特定的,但以相同的方式实例化:
- 使用SQL身份验证的相同连接字符串
- 两个DataContext都将其CommandTimeout从默认值设置为60秒
- DataContext的所有其他配置选项都是默认选项
构建Linq查询的方式对于项目来说并不完全相同,但生成的Linq查询是相同的。生成的(T-)SQL select语句也是一样的(监控并验证数据库服务器上的SQL句柄)
数据库服务器为:
- Microsoft SQL Server Enterprise 2005 x64(9.00.4035.00)
- 操作系统:Microsoft Server 2003 R2 SP2 x64
如果运行,则项目"A"的查询的监控CPU时间(在数据库服务器上)急剧增加,并引发命令超时异常。(System.Data.SqlClient.SqlException:超时已过期)
另一方面,"B"的查询在秒内执行(大约3)。我能够通过再次调用具有相同参数的代码"A"来再现行为(不对代码或数据库进行更改)。"B"甚至在几秒钟内执行,同时"A"正在增加其CPU时间。
很遗憾,在一位同事重新创建指数后,我再也无法谴责这种行为了同一位同事提到,查询在"上个月"运行得很快(尽管没有代码从"上月"更改…)
我调试了这两个项目的代码——两个DataContext实例看起来都很相似。数据库服务器进程的sql句柄包含相同的sql语句。但是"A"抛出超时异常,"B"在几秒钟内执行——重复!
为什么对于项目"A",相同的Linq到SQL查询在数据库服务器上消耗的CPU时间比对于"B"要多得多
确切地说:如果查询由于重复的原因而运行"慢",那么同一个查询怎么能因为被另一个Linq-To-SQL代码调用而运行得更快呢?
会有我还不知道的副作用吗?是否有一些DataContext的实例值需要我在运行时专门查看?
顺便说一句:SQL语句通过SSMS在每次运行中使用相同的查询计划。
为了完整起见,我链接了一个示例:
- 项目"B"的C#代码片段(两个项目的SqlRequest.GetQuery部分看起来相似)
- SQL文件包含适当的数据库架构
- 数据库执行计划
请记住,我不能透露完整的数据库模式、代码或我正在查询的实际数据。(SQL表除了命名的列之外还有其他列,C#代码有点复杂,因为Linq查询是有条件构建的。)
更新-在运行时获得更多见解
两个DataContext
实例的一些性质:
Log = null;
Transaction = null;
CommandTimeout = 60;
Connection: System.Data.SqlClient.SqlConnection;
SqlConnection是从这样的连接字符串创建的(两种情况):
"Data Source=server;Initial Catalog=sourceDb;Persist Security Info=True;User ID=user;Password=password"
没有运行显式SqlCommands将SET
选项传递到数据库会话。两者都不包含内联TVF SET
选项。
您需要在SQL Server上运行跟踪,而不是从C#端进行调试。这将显示A
和B
在服务器上执行的所有内容。执行计划对你没有好处,因为它恰恰是一个计划。您希望查看精确的语句及其实际性能指标。
在极少数情况下,您告诉我,两个SELECT
语句完全相同,但性能大不相同。我几乎可以肯定,它们在不同的事务隔离级别下运行。即使您没有显式创建任何SQL命令,单个SQL命令也是一个隐式事务。
无论出于何种原因,如果跟踪没有表明,您应该发布正在运行的命令及其度量。
注意:运行跟踪会带来一些性能开销,所以我会尽量缩短时间段,或者尽可能在非高峰时段运行。
我认为您将在"A"项目edmx文件中检查LazyLoadingEnabled="true"。
如果LazyLoadingEnabled="true":在延迟加载的情况下,相关对象(子对象)在被请求之前不会自动与其父对象一起加载。默认LINQ支持延迟加载。
IF LazyLoadingEnabled="false":在急切加载的情况下,相关对象(子对象)将与其父对象一起自动加载。要使用Eagle加载,您需要使用Include()方法。