我正在使用 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应用不同的查询计划??
我已经发布到MSDN 论坛和 sourceforge JTDS 论坛(主题:“在 JTDS 中存储 proc 比直接在 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:466,514 读取:142,478,387 写入:284,078 持续时间:983,796
SSMS:CPU:466,973 读取:142,440,401 写入:280,244 持续时间:769,851
(都在分析之前运行 DBCC DROPCLEANBUFFERS,并且都产生正确的行数)
所以我的结论是它们都执行相同的读取和写入,只是它们执行的方式不同,你们怎么看?
事实证明,不同客户端的查询计划有很大不同(Java 客户端在插入期间更新索引,而不是在更快的 SQL 客户端中,此外,它执行连接的方式也不同(嵌套循环 Vs.收集流,嵌套循环与索引扫描,啊!))。为什么会这样,我还不知道(当我找到它的底部时我会重新发布)
结语
我无法让它正常工作。我尝试同质化Java 和 Mgmt studio 客户端之间的连接属性(等)arithabort
。ansi_nulls
最终,两个不同的客户端具有非常相似的查询/执行计划(但仍然具有不同的实际 plan_id)。我在 MSDN SQL Server 论坛上发布了我发现的摘要,因为我发现不仅在 JDBC 客户端和管理工作室之间,而且在微软自己的命令行客户端 SQLCMD 之间也存在不同的性能,我还检查了一些更激进的事情,比如网络流量太,或者将存储过程包装在另一个存储过程中,只是为了笑。
我有一种感觉,问题出在游标执行方式的某个地方,它以某种方式导致 Java 进程被挂起,但是为什么不同的客户端应该在没有其他东西运行的情况下产生这种不同的锁定/等待行为并且相同的执行计划在运行中有点超出我的技能(我不是 DBA!)。
结果,我决定 4 天足够任何人的时间浪费在这样的事情上,所以我会勉强围绕它进行编码(如果我说实话,存储过程需要重新编码以增加增量而不是重新编码) - 无论如何每周计算所有数据),并将这个记录下来以体验。我会留下这个问题,非常感谢所有把帽子放在戒指上的人,这一切都很有用,如果有人想出更多的东西,我很想听听更多的选择......如果有人找到这篇文章是在他们自己的环境中看到这种行为的结果,然后希望这里有一些你可以自己尝试的指示,并希望比我们更深入地了解。
我现在准备好我的周末了!
-詹姆士