我们有一个应用程序,它给人的每一印象都是因为数据库响应不佳而受到瓶颈。数据库和应用程序服务器都没有大量加载,但是应用程序花费了大量时间通过ExecuteReader进行查询。
我们正在测量两件事:SQL Server Profiler中的批处理和语句持续时间,以及调用ExecuteReader和处理它之间的时间。消费数据是“微不足道的”即。只需将数据读入字典列表即可。
Profiler记录的持续时间通常远低于应用程序记录的持续时间。这些查询只返回几行(通常是一行),因此使用结果集所需的时间应该很小。 但是我们已经看到应用程序记录了超过1700ms的150ms查询(由分析器记录)的实例。
环境:
显而易见的罪魁祸首是网络延迟,但ping
表示从应用程序到数据库服务器的延迟始终小于1毫秒。
连接被重用于多个查询,因此Open() - 时间开销应该已经单独计算。我会期待这可以排除ExecuteReader期间的身份验证延迟,但也许我错了吗?
我们应该调查哪些其他内容? ExecuteReader可能会等待哪些其他内容?
答案 0 :(得分:2)
我们已经看到150ms查询的实例(由分析器记录)被应用程序记录为超过1700ms。
确切地说,该应用程序如何记录持续时间?使用StopWatch
,还是那种性质的东西?或者来自SqlConnection.RetrieveStatistics()报告的客户统计信息?
您是否检查过运行查询的请求的等待类型字段?在sys.dm_exec_requests DMV中,有四个字段包含可能在此处有用的信息:wait_type
,wait_time
,last_wait_type
和wait_resource
。即使查询在内部快速将结果返回给SQL Server,它仍然需要用一个线程将这些结果发送回调用者。
另外,有些事情只是为了帮助缩小可能性:
关闭连接池。在ConnectionString中,使用Pooling=false;
。这仍然允许在同一连接上进行多次查询(因此不会干扰临时表的使用)。是的,它会略微增加总体时间,因为它需要对每个连接进行身份验证,但它会排除某些问题,并且会停止"。
如果可能(尚未执行此操作),请在CommandBehavior.SequentialAccess
的调用中指定ExecuteReader()
。这可以防止在调用SqlDataReader.Read()
时整行的本地缓存,这有助于当你有大量的字符串和/或二进制值,甚至没有检索,或者如果有很多列,你只是抓住一个少。