我正在使用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中的存储过程比直接在DB中慢”)我想知道是否有人对于为什么会发生这种情况有任何建议?
提前致谢,
-James
(N.B。不要害怕,我会在找到解决方案后整理其他论坛中的所有答案)
Java code snippet:
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客户端中,同样,它执行连接的方式也不同(嵌套) loop Vs.收集流,嵌套循环Vs索引扫描,唉!))。这就是为什么,我还不知道(当我到底时,我会重新发帖)
后记
我无法让它正常工作。我尝试在Java和Mgmt studio客户端之间同化连接属性(arithabort
,ansi_nulls
等)。它最终导致两个不同的客户端具有非常相似的查询/执行计划(但仍然具有不同的实际plan_ids)。我发布了the MSDN SQL Server forums所发现的摘要,因为我发现不仅在JDBC客户端和管理工作室之间,而且在Microsoft自己的命令行客户端SQLCMD之间有不同的性能,我还检查了一些更激进的事情,如网络流量也可以将存储的proc包装在另一个存储过程中,只是为了咧嘴笑。
我有一种感觉问题出在游标执行方式的某个地方,并且它以某种方式导致Java进程被暂停,但为什么不同的客户端应该在什么时候产生这种不同的锁定/等待行为其他正在运行并且运行相同的执行计划有点超出我的技能(我不是DBA!)。
结果,我已经决定用4天时间浪费在这样的事情上,所以我会勉强编写代码(如果我诚实的话,存储过程需要重新编码才能更加增量而不是每周重新计算所有数据),并将这个数据用于体验。我会把这个问题保持开放,非常感谢所有把帽子戴在戒指上的人,这一切都很有用,如果有人想出更进一步的话,我很想听到更多的选择......如果有人发现的话这篇文章是在他们自己的环境中看到这种行为的结果,然后希望这里有一些你可以自己尝试的指针,希望能比我们更充分地看到它。
我现在已经准备好了周末!
-James
答案 0 :(得分:4)
您可以为事件SQL:BatchCompleted和SP:Completed附加事件探查器和监视器,并使用持续时间过滤器> 1000.从Java客户端和SSMS运行该过程。比较两个事件的读取和写入(Java与SSMS)。他们有显着的不同吗?这将表明执行路径或计划有很大不同,I / O存在显着差异。
还尝试捕获两者的Showplan XML事件并比较计划(将事件保存为.sqlplan文件,在SSMS中打开以便于分析)。他们有类似的计划吗?估计与实际(行,倒带,重新绑定)之间是否存在巨大差异?他们有相同程度的并行性吗?可以从sys.dm_exec_requests视图中检索计划。
是否有任何警告事件,例如Missing Column Statistics,Sort Warnings,Hash Warning,Execution Warnings,Blocked Process?
关键是你可以随意使用一整套调查工具。一旦找到差异的根本原因,就可以将其追溯到Java环境设置和SSMS环境(ADO.Net SqlClient)之间的不同之处。默认事务隔离级别,ANSI设置等等。
答案 1 :(得分:2)
检查:您的问题是两个应用程序(SSMS,Java)对SQL Server进行完全相同的相同调用,并且SQL Server对每个应用程序采取不同的行为?如果是这样的话,我每隔一两年就会碰到这样的事情,而且他们几天都在伤害我的大脑。
有一次,我最终隔离了每个进程调用并记录了Profiler中整个进程的所有。我最终注意到Login事件(在TextData下)显示了大量信息,如下所示:
-- 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
“现有连接”事件也将显示此信息 - 但是,有时会立即发送后续调用(批次,RPC,我刚刚发布)[ ISQL或OSQL这样做,我认为]立即重置其中一些 - Arithabort和Quoted_Identifier似乎是最受欢迎的,其他SET选项也会根据应用程序数据库界面使用的任何连接协议的设置或要求进行修改。
另一个:某些设置在“创建”时保留为过程的属性,而其他设置在编译时被考虑在内。一方面,连接的SET值可能被创建过程时保存的配置覆盖;另一方面,您的两个连接可能差异很大,以至于为一个过程生成了两个执行计划。 (经过充分研究后,所有这些信息都可以在系统表和DMV中找到。)
简而言之,在我看来,SQL的晦涩难过让你搞砸了。直到今天,我厌恶所有这些goombah设置。我注意到的事情一直在搞乱他们[我的意思是,真的,傻瓜会为连接池设置implicit_transaction?但是一旦他们做到了......]当地面(规则)不断从你下面改变时,很难建造结构。毕竟,请记住那个人在沼泽地建造城堡的说法......
答案 2 :(得分:2)
我记得前一段时间有类似的问题,因为JTDS正在静默地将字符串参数转换为Unicode或类似的东西。由于该转换,SQL Server无法使用从SSMS运行存储过程时使用的索引。
HIH
答案 3 :(得分:0)
Java案例是否包括将结果传输到Java服务器(网络开销)以及一些Java处理? 12分钟的查询可能会产生大量数据。
答案 4 :(得分:0)
如果您正在查看分析器并且执行之间没有区别,那么差异必须与客户端系统有关。
4分钟似乎只是为了准备发送声明,所以12分钟的等待必然会产生一些其他影响 - 不知道它是什么。答案 5 :(得分:0)
我不确定这篇文章是否仍然相关。我们在申请中遇到了类似的问题。
在SQL Management Studio中运行存储过程与从JDBC运行存储过程之间的一个关键区别是事务上下文。如果在Java中使用ORM,则默认情况下,存储过程在事务上下文中运行。在SQL管理工作室中直接运行存储过程时,事务处于关闭状态。性能差异很大。
答案 6 :(得分:-1)
对不起,我没有找到正确的答案,所以我不想将其中的任何一个分配正确,所以我打算将这个答案标记为正确,并希望任何人遇到任何相似的运气!
答案 7 :(得分:-1)
您是否知道Microsoft为其数据库提供了JDBC驱动程序?
这些可能更具性能。
显然......你现在可能已经解决了这个问题。