我正在使用 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 论坛 http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/9fd72536-f714-422a-b4c9-078e2ef365da/和 sourceforge JTDS 论坛(主题:“JTDS 中的存储过程比 DB 中的直接存储过程慢”)我想知道是否有人对为什么会发生这种情况有任何建议?
提前致谢,
-James
(注意,不要害怕,一旦找到解决方案,我会将我在其他论坛中获得的所有答案整理在一起)
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 客户端中则没有),而且执行连接的方式也不同(嵌套循环与循环)。收集流、嵌套循环与索引扫描,啊!))。到底为什么会这样,我还不知道(当我真正了解它的底部时,我会重新发布)
Epilogue
我无法让它正常工作。我尝试均匀化连接属性(arithabort
, ansi_nulls
等)在 Java 和 Mgmt studio 客户端之间。最终两个不同的客户端具有非常相似的查询/执行计划(但仍然具有不同的实际 plan_id)。我发布了我发现的内容的摘要MSDN SQL Server 论坛 http://social.msdn.microsoft.com/Forums/en-US/sqldataaccess/thread/8976b4ad-1bcd-4c9d-a1d9-08325fbe6ac6因为我发现不仅 JDBC 客户端和管理工作室之间存在性能差异,而且 Microsoft 自己的命令行客户端 SQLCMD 之间也存在性能差异,因此我还检查了一些更激进的东西,例如网络流量,或者将存储过程包装在另一个存储过程中,只是为了咧嘴一笑。
我感觉问题出在游标执行方式的某个地方,并且它以某种方式导致 Java 进程被挂起,但是为什么不同的客户端在没有其他东西运行时会产生这种不同的锁定/等待行为并且相同的执行计划正在运行有点超出了我的技能范围(我不是DBA!)。
结果,我决定 4 天足够任何人浪费在这样的事情上的时间,所以我会勉强地围绕它进行编码(如果我诚实的话,存储过程需要重新编码以增加增量而不是重新编码) -无论如何每周计算所有数据),并将这一点归结为经验。我将保留这个问题,非常感谢所有参与其中的人,这都很有用,如果有人提出任何进一步的建议,我很乐意听到更多选择......如果有人发现这篇文章是在他们自己的环境中看到这种行为的结果,然后希望这里有一些提示您可以自己尝试,并希望比我们看得更远。
我现在已经准备好迎接周末了!
-James