如果我的桌面应用程序使用ADO.Net连接到SQL Server 2008 R2并使用ad hoc参数化查询来检索数据,那么当应用程序的两个不同实例运行查询时会发生什么?第一个调用是否已编译,第二个调用是否使用内存中的版本?
示例查询:
SqlConnection conn = new SqlConnection(_connectionString);
conn.Open();
string s = "SELECT email, passwd, login_id, full_name " +
"FROM members WHERE email = @email";
SqlCommand cmd = new SqlCommand(s);
cmd.Parameters.Add("@email", email);
SqlDataReader reader = cmd.ExecuteReader();
第一次触发查询并且连续调用看起来很好时,我注意到查询性能很慢。我只是想知道这是否是每个应用程序实例的全面行为,或者如果第一次从一个实例触发查询,它会提高使用此查询的应用程序的所有实例的性能。
答案 0 :(得分:2)
SQL Server必须在第一次获取查询时对其进行分析,并为其找到一个相当好的执行计划。
一旦完成,查询
SELECT email, passwd, login_id, full_name FROM members WHERE email = @email
及其执行计划存储在计划缓存中。
只要计划缓存有足够的空间,然后任何后续执行完全相同的查询(“相同”到最后一个逗号,空格或任何内容!它必须是绝对相同的 SQL)将从计划缓存中重用该执行计划。
所以是的 - 第一次执行查询(例如在SQL Server重新启动之后),稍有延迟就会引起注意,但是一旦执行它并且查询计划被缓存,它应该表现得更好 - 对于<强>所有连接到将使用完全相同查询的SQL Server。
对完全相同的查询的要求也说明了为什么它如此糟糕 - 从性能的角度来看 - 自己将SQL串起来并将查询值放入实际的查询文本中 - 这样,每个查询都带有新值是一个新的SQL查询文本,必须为每个请求重复整个故事。如果您正在使用参数化查询,那么查询将保持不变,因此可以重用缓存的执行计划 - 只有参数值更改,但这不会影响查询执行计划以及重用缓存计划的能力
答案 1 :(得分:0)
我认为编译和计划缓存在这里并不重要(你的SQL请求很简单)。更重要的是磁盘缓存。看来,第一次从磁盘进行物理读取,下次有逻辑读取(来自缓冲区缓存)。此磁盘缓存是服务器范围的。
您可以尝试添加命令
DBCC DROPCLEANBUFFERS
befor you request,强制清理磁盘缓存。所以你可以检查性能
答案 2 :(得分:0)
是的,参数化查询执行计划被兑现并重复用于每个连接,直到它们将从cashe中推送出来。您可以检查计划是否在事件SP:Recompile
的Profiler中重新编译。有关它的更多信息,请参阅MSDN文章Execution Plan Caching and Reuse
但是,在您的情况下,我认为,更重要的角色扮演着数据的兑现。只要您执行查询,第一次将数据页加载到RAM中并保持在那里,直到它们从cashe中被推出。如果它们将相同的值传递给@email
参数,或者您没有字段email
(或两者)上的索引,则会影响后续查询的执行时间。