通过Java运行的存储过程比直接在数据库上运行慢30%

通过Java运行的存储过程比直接在数据库上运行慢30%,java,sql,sql-server,stored-procedures,jtds,Java,Sql,Sql Server,Stored Procedures,Jtds,我正在使用Java1.6、JTDS1.2.2(也只是尝试了1.2.4,但没有效果)和SQLServer2005创建CallableStatement来运行存储过程(没有参数)。我看到Java包装器运行相同的存储过程比使用SQLServerManagementStudio慢30%。我已经运行了MS SQL profiler,两个进程之间的I/O差别不大,因此我认为这与查询计划缓存无关 存储的进程不接受任何参数,也不返回任何数据。它使用服务器端游标来计算填充表所需的值 我看不出从Java调用一个存储

我正在使用Java1.6、JTDS1.2.2(也只是尝试了1.2.4,但没有效果)和SQLServer2005创建CallableStatement来运行存储过程(没有参数)。我看到Java包装器运行相同的存储过程比使用SQLServerManagementStudio慢30%。我已经运行了MS SQL profiler,两个进程之间的I/O差别不大,因此我认为这与查询计划缓存无关

存储的进程不接受任何参数,也不返回任何数据。它使用服务器端游标来计算填充表所需的值

我看不出从Java调用一个存储过程会增加30%的开销,当然这只是一个到数据库的管道,SQL被发送下来,然后数据库执行它……数据库会给Java应用程序一个不同的查询计划吗

我已经在这两个论坛以及sourceforge JTDS论坛(主题:“JTDS中的存储过程比DB中的直接过程慢”)上发过帖子,我想知道是否有人对为什么会发生这种情况有任何建议

提前感谢,

-詹姆斯

(注意:不用担心,一旦找到解决方案,我将整理我在其他论坛上得到的所有答案)

Java代码片段:

sLogger.info("Preparing call...");
stmt = mCon.prepareCall("SP_WB200_POPULATE_TABLE_limited_rows");
sLogger.info("Call prepared.  Executing procedure...");
stmt.executeQuery();
sLogger.info("Procedure complete.");
我已运行sql profiler,并发现以下内容:

Java应用程序: CPU:466514读取:142478387写入:284078持续时间:983796

SSMS: CPU:466973读取:142440401写入:280244持续时间:769851

(使用DBCC DROPCLEANBUFFERS的两个都在分析之前运行,并且都生成正确的行数)

所以我的结论是,它们都执行相同的读写操作,只是它们的方式不同,你们怎么看

结果表明,不同客户机的查询计划明显不同(Java客户机在插入过程中更新的索引不在更快的SQL客户机中,而且它执行连接的方式也不同(嵌套循环与聚集流、嵌套循环与索引扫描,argh!))。为什么会这样,我还不知道(等我弄清楚了再发)

结语

我不能让它正常工作。我尝试在Java和Mgmt studio客户端之间对连接属性(
arithabort
ansi_nulls
等)进行同质化。结果是,两个不同的客户机具有非常相似的查询/执行计划(但实际的计划ID仍然不同)。我将我的发现汇总到了,因为我发现不仅JDBC客户机和management studio之间,而且微软自己的命令行客户机SQLCMD之间的性能都有所不同。我还检查了一些更激进的事情,比如网络流量,或者将存储过程包装到另一个存储过程中,只是为了好玩

我有一种感觉,问题在于游标的执行方式,它在某种程度上导致了Java进程被挂起,但是,当没有其他任何东西在运行并且相同的执行计划正在运行时,为什么不同的客户机会导致这种不同的锁定/等待行为,这超出了我的能力(我不是DBA!)

因此,我决定任何人在这样的事情上浪费4天的时间就足够了,所以我会勉强围绕它进行编码(如果我诚实的话,存储过程需要重新编码以增加增量,而不是每周重新计算所有数据)我会把这个问题留待讨论,非常感谢所有参加比赛的人,这一切都很有用,如果有人提出进一步的建议,我很想听到更多的选择……如果有人在自己的环境中看到这种行为后发现了这篇文章,那么希望有一些这里的指针,您可以尝试自己,并希望充分看到比我们做得更远

我已经准备好过周末了


-James

Java案例是否包括将结果传输到Java服务器(网络开销)以及一些Java处理?一个12分钟的查询可能会产生相当大的数据量。

如果您正在查看探查器,并且执行之间没有差异,那么差异一定在于客户端系统


仅仅准备一个要发送的语句就需要4分钟,因此12分钟的等待肯定会产生一些其他影响——不知道是什么影响。

您可以附加事件探查器和监视器,并在持续时间>1000的情况下使用筛选器。从Java客户端和SSM运行该过程。比较两个事件的读写(Java和SSM)。它们有显著的不同吗?这表明执行路径或计划有显著的不同,在I/O方面有显著的差异

还要尝试捕获这两个事件并比较计划(将事件保存为.sqlplan文件,在SSMS中打开以便于分析)。它们是否有类似的计划?估计值与实际值(行、倒带、重新绑定)是否存在巨大差异?它们是否具有相同的并行度?可以从视图中检索计划

是否引发了任何警告事件,例如


关键是,您可以使用一整套调查工具。一旦找到差异的根本原因,就可以追溯到Java环境设置与SSMS环境(ADO.Net SqlClient)之间的差异。默认事务隔离级别、ANSI设置等。

检查:您的问题是两个应用程序(SSM、Java)对SQL Server进行完全相同的调用,而SQL Server对每个应用程序的操作都不同吗?如果是这样,我每一两年都会遇到类似的问题,它们会伤害我的大脑好几天

有一次,我最终隔离了每个进程调用,并在Profiler中记录了整个进程的所有内容
-- network protocol: TCP/IP
set quoted_identifier on
set arithabort off
set numeric_roundabort off
set ansi_warnings on
set ansi_padding on
set ansi_nulls on
set concat_null_yields_null on
set cursor_close_on_commit off
set implicit_transactions off
set language us_english
set dateformat mdy
set datefirst 7
set transaction isolation level read committed