Java 为什么Microsoft SQL Server 2012查询在JDBC 4.0上只需几分钟,而在Management Studio中只需几秒钟?
在从远程Microsoft SQL Server 2012向使用Microsoft JDBC Driver 4.0的Java客户端检索相对较大的Java 为什么Microsoft SQL Server 2012查询在JDBC 4.0上只需几分钟,而在Management Studio中只需几秒钟?,java,sql-server,jdbc,sql-server-2012,Java,Sql Server,Jdbc,Sql Server 2012,在从远程Microsoft SQL Server 2012向使用Microsoft JDBC Driver 4.0的Java客户端检索相对较大的时,我正在处理一个明显的性能问题 当我在远程服务器的Microsoft SQL server Management Studio上运行相应的查询时,它几乎会立即返回大约220k行。当我从客户端发出相同的查询时,它会暂停。同样的测试在早期版本的数据库上也很好地工作,其中只有大约400行符合条件 我试图通过添加来解决这个问题;responseBufferin
时,我正在处理一个明显的性能问题
当我在远程服务器的Microsoft SQL server Management Studio上运行相应的查询时,它几乎会立即返回大约220k行。当我从客户端发出相同的查询时,它会暂停。同样的测试在早期版本的数据库上也很好地工作,其中只有大约400行符合条件
我试图通过添加来解决这个问题;responseBuffering=adaptive“
到传递给DriverManager.getConnection()
的URL。建立连接后,我在的结果中看到此属性(以及其他属性),但[返回null
,而且客户端仍在暂停
这里可能会出现什么问题?我如何指示Microsoft SQL Server(不仅仅是以Java编程的方式向它建议)必须以较小的块返回行,而不是一次返回所有行,或者通过其他措施改进JDBC查询时间
另外两个观察结果似乎有些奇怪,可能指向完全不同的根本原因:
- 当客户端暂停时,它仍然只显示相对较轻的CPU负载,这与我期望的大量垃圾收集不同
- “responseBuffering=adaptive”现在应该是正常的
PreparedStatement
切换到Statement
并不能改善我的情况(显然在某些情况下会有所帮助)
更新以下是我当前的查询:
select
PARENT.IDENTIFIER as PARENT_IDENTIFIER,
PARENT.CLASS as PARENT_CLASS,
CHILD.TYPE as CHILD_TYPE,
CHILD.IDENTIFIER as CHILD_IDENTIFIER,
PROPERTY.IDENTIFIER as PROPERTY_IDENTIFIER,
PROPERTY.DESCRIPTION as PROPERTY_DESCRIPTION,
PROPERTY.TYPE as PROPERTY_TYPE,
PROPERTY.PP as PROPERTY_PP,
PROPERTY.STATUS as PROPERTY_STATUS,
PROPERTY.TARGET as PROPERTY_TARGET -- a date
from
OBJECTS as CHILD
left outer join RELATIONS on RELATIONS.CHILD = CHILD.IDENTIFIER
left outer join OBJECTS as PARENT on RELATIONS.PARENT = PARENT.IDENTIFIER
inner join PROPERTIES as PROPERTY on PROPERTY.OBJECT = CHILD.IDENTIFIER
where
PROPERTY.TARGET is not null
order by
case when PARENT.IDENTIFIER is null then 1 else 0 end,
PARENT.IDENTIFIER,
CHILD.IDENTIFIER,
PROPERTY.TARGET,
PROPERTY.IDENTIFIER
也许,Microsoft文档中的此链接可以帮助您解决问题: 特别是在“自适应缓冲使用指南”部分: 在某些情况下,使用selectMethod=cursor而不是responseBuffering=adaptive会更有益,例如: 如果应用程序缓慢地处理一个只读的前向结果集,例如在用户输入后读取每一行,那么使用selectMethod=cursor而不是responseBuffering=adaptive可能有助于减少SQL Server的资源使用 如果应用程序在同一连接上同时处理两个或多个只读的正向结果集,则使用selectMethod=cursor而不是responseBuffering=adaptive可能有助于减少驱动程序在处理这些结果集时所需的内存
在这两种情况下,您需要考虑创建、读取和关闭服务器游标的开销。
< P>我只想抛出这个建议,留给您进行测试。 JDBC驱动程序可能会在返回之前获取所有行,而另一个系统只是返回打开的游标 我在使用JDBC的其他数据库上见过这种行为,但没有直接使用SQL Server的经验 在我看到的示例中,将连接的自动提交设置为false会阻止它加载整个结果集但这很可能是您面临的根本问题。自适应缓冲是一个很好的答案。我还建议您通过SQL Server Profiler检查连接设置选项 启动跟踪时,请确保选择了
ExistingConnections
。比较JDBC连接和SSMS连接中的SPID。ARITHABORT
是我看到的导致SSMS和JDBC驱动程序之间性能差异的一种类型。Microsoft在此处简要提及:。此处堆栈交换信息:
在Oracle上,我看到了对语句
/PreparedStatement
对象使用setFetchSize
方法的巨大影响。显然,SQL Server驱动程序不支持该方法。但是,驱动程序中有一个内部方法用于该方法。有关详细信息,请参阅
另外,在while(rs.next())
循环中你在做什么?除了阅读一列之外,不要做任何事情,比如rs.getInt(1)
。看看会发生什么。如果它飞起来,这表明瓶颈在你以前处理结果集的过程中。如果它仍然很慢,那么问题一定在驱动程序或数据库中
您可以使用SQL Server Profiler来比较通过JDBC进入的执行和通过SSMS运行的执行。比较CPU、读取、写入和持续时间。如果它们不同,则执行计划可能不同,这让我回到了我提到的第一件事:
设置
选项。我们在事实证明,这是由于缓存。我们查阅了一本非常好的阅读资料
SQL Server缓存执行计划,您可以使用以下方式查看它:
select * from sys.dm_exec_cached_plans
对我们来说,有效的方法是忽略缓存的执行计划来处理慢查询
对于不同的查询,优化阶段可能会考虑查询的参数值,因为在某些情况下,使用不同的执行计划更有意义
如果执行计划已被缓存,并且存在缓存命中(使用忽略参数的prepared语句),则对于具有不同参数的同一查询,执行计划可能是次优的
要验证这一点,您可以尝试还原一些查询,并查看是否为具有不同参数的同一查询获得不同的执行计划
如果事实证明是这样,您可以做以下几件事:
- 要立即获得结果,请向查询中添加重新编译提示
。这将每次重新编译查询,但可能会导致选项(重新编译)