【发布时间】:2010-12-19 22:11:37
【问题描述】:
我正在使用 Java 1.6、JTDS 1.2.2(也只是尝试 1.2.4 无济于事)和 SQL Server 2005 来创建 CallableStatement 来运行存储过程(不带参数)。我看到运行相同存储过程的 Java 包装器比使用 SQL Server Management Studio 慢 30%。我已经运行了 MS SQL 分析器,两个进程之间的 I/O 差别不大,所以我认为这与查询计划缓存无关。
存储的过程不接受任何参数并且不返回任何数据。它使用服务器端游标来计算填充表所需的值。
我看不出从 Java 调用存储过程应该如何增加 30% 的开销,当然它只是一个到数据库的管道,SQL 被发送下来,然后数据库执行它......数据库可以是给 Java 应用一个不同的查询计划??
我已经在the MSDN forums 和 sourceforge JTDS 论坛上发帖(主题:“在 JTDS 中存储 proc 比直接在 DB 中慢”)我想知道是否有人对为什么会发生这种情况有任何建议?
提前致谢,
-詹姆斯
(请注意,不要害怕,一旦找到解决方案,我会在这里整理我在其他论坛中获得的任何答案)
Java 代码 sn-p:
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:466,514 读取:142,478,387 写入:284,078 持续时间:983,796
SSMS: CPU:466,973 读取:142,440,401 写入:280,244 持续时间:769,851
(在分析之前运行 DBCC DROPCLEANBUFFERS,并且都产生正确的行数)
所以我的结论是它们都执行相同的读取和写入,只是它们执行的方式不同,你们怎么看?
事实证明,不同客户端的查询计划明显不同(Java 客户端在插入期间更新索引,而不是在更快的 SQL 客户端中,此外,它执行连接的方式也不同(嵌套循环与收集流,嵌套循环与索引扫描,啊!))。为什么会这样,我还不知道(我会在深入了解后重新发布)
结语
我无法让它正常工作。我尝试同质化 Java 和 Mgmt Studio 客户端之间的连接属性(arithabort、ansi_nulls 等)。最终,两个不同的客户端具有非常相似的查询/执行计划(但仍然具有不同的实际 plan_id)。我在the MSDN SQL Server forums 上发布了我发现的摘要,因为我发现不仅在 JDBC 客户端和管理工作室之间,而且在微软自己的命令行客户端 SQLCMD 之间也存在不同的性能,我还检查了一些更激进的事情,比如网络流量,或者将存储过程包装在另一个存储过程中,只是为了笑。
我感觉问题出在游标执行方式的某个地方,它以某种方式导致 Java 进程被挂起,但是为什么不同的客户端应该在什么都没有的情况下产生这种不同的锁定/等待行为else 正在运行并且相同的执行计划正在运行,这超出了我的技能(我不是 DBA!)。
因此,我决定 4 天的时间足以让任何人浪费在这样的事情上,所以我会勉强围绕它编写代码(老实说,存储过程需要重新编写代码以增加增量而不是每周重新计算所有数据),并将这个记录下来以体验。我会留下这个问题,非常感谢所有把帽子放在戒指上的人,这一切都很有用,如果有人想出更多的东西,我很想听听更多的选择......如果有人找到这篇文章是在他们自己的环境中看到这种行为的结果,那么希望这里有一些建议您可以自己尝试,并希望比我们更深入地了解。
我现在已经为我的周末做好准备了!
-詹姆斯
【问题讨论】:
-
在您的 JDBC 代码中,您使用的是
CallableStatement、PreparedStatement还是Statement? -
Java 案例的时间安排在哪里?在数据库中?在 Java 领域完成查询?结果处理 Java 完成后?
-
我正在使用 CallableStatement。 Java 案例的时序来自于日志记录语句。作为参考,我们在 MGMT 工作室谈了大约 12 分钟,Vs。约 16 分钟的 Java 语言。
标签: java sql sql-server stored-procedures jtds