代码之家  ›  专栏  ›  技术社区  ›  James B

存储的进程通过Java慢速运行30%,而不是直接运行在数据库上

  •  10
  • James B  · 技术社区  · 15 年前

    我使用Java 1.6、JTDS1.2.2(也只是尝试1.2.4无用处)和SQL Server 2005来创建一个CALABLE语句来运行一个存储过程(没有参数)。我看到Java包装器运行相同的存储过程30%比使用SQLServer Management Studio慢。我已经运行了MS SQL事件探查器,两个进程之间的I/O几乎没有区别,所以我认为这与查询计划缓存无关。

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

    我看不出调用Java存储的PROC应该如何增加30%的开销,当然这只是SQL发送给数据库的一个管道,然后数据库执行它……数据库可以给Java应用程序一个不同的查询计划吗??

    我已经发到两个 the MSDN forums 以及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事件探查器,并发现了以下内容:

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

    SSMS: CPU:466973读:14240401写:280244持续时间:769851

    (这两种方法都使用DBCC DropCleanBuffers在分析之前运行,并且都会产生正确的行数)

    所以我的结论是,他们都执行相同的读和写,只是他们的方式不同,你们怎么想?

    事实证明,对于不同的客户端,查询计划有很大的不同(Java客户端在一个不在更快的SQL客户端中插入的索引中更新索引,而且,它正在执行的连接方式是不同的(嵌套循环与收集流、嵌套循环与索引扫描、ARGH!))这就是为什么,我还不知道(我会在到达底部后重新发布)

    后记

    我不能让这个正常工作。我试图使连接属性均匀化。( arithabort , ansi_nulls 在Java和MGMT Studio客户端之间。最后,两个不同的客户机有非常相似的查询/执行计划(但实际计划的ID仍然不同)。我张贴了一份我发现的摘要 the MSDN SQL Server forums 由于我发现JDBC客户机和Management Studio的性能不同,而且微软自己的命令行客户机sqlcmd的性能也不同,我还检查了一些更激进的东西,比如网络流量,或者将存储过程包装在另一个存储过程中,只是为了GRIN。

    我有一个问题,问题在于光标执行的方式,它在某种程度上引起了Java进程被暂停,但是为什么一个不同的客户端应该在没有其他的运行和执行相同的执行计划时产生这种不同的锁定/等待行为,这超出了我的技能。没有DBA!.

    因此,我决定4天的时间足够任何人浪费在这样的事情上,所以我不情愿地对它进行编码(如果我诚实地说,存储过程需要重新编码,使其更加增量,而不是每周重新计算所有数据),并将这一天记下来进行体验。我会让这个问题保持开放,非常感谢每个戴帽子的人,这一切都是有用的,如果有人想做更多的事情,我希望听到更多的选择……如果有人发现这篇文章是因为在他们自己的环境中看到这种行为,那么希望这里有一些提示,你可以尝试自己,希望比我们看到的更多。

    我准备好周末了!

    -杰姆斯

    8 回复  |  直到 10 年前
        1
  •  4
  •   Remus Rusanu    15 年前

    您可以附加事件探查器并监视事件 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环境设置和SSM环境(ADO.Net SqlClient)之间的不同。例如默认事务隔离级别、ANSI设置等。

        2
  •  2
  •   Philip Kelley    15 年前

    检查:您的问题是两个应用程序(SSMS,Java)对SQL Server的调用完全相同,而SQLServer对每个服务器的作用不同吗?如果是这样的话,我每年或两年都会碰到这样的事情,它们会伤到我的大脑好几天。

    有一次,我最终隔离了每个进程调用和日志记录 一切 对于探查器中的整个进程。我最终注意到登录事件(在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
    

    “现有连接”事件也将显示此信息,但有时会立即发送后续调用(批处理、rpcs、i dismember刚才)。[ 我想是ISQL或OSQL做的 ]要立即重置其中一些--arithabort和带引号的\标识符似乎是最受欢迎的,其他设置选项也会根据应用程序数据库接口使用的任何连接协议的设置或要求进行修改。

    另一种方法:一些设置在“创建”时作为过程的属性保存,而其他设置在编译时作为因子。一方面,您的连接的设置值可能会被创建过程时保存的配置覆盖;另一方面,您的两个连接可能差异很大,以至于为一个过程生成了两个执行计划。(经过充分研究,所有这些信息在系统中都可用。表格和DMV。)

    简言之,在我看来,SQL的模糊性把你搞得一团糟。直到今天,我都讨厌这些高棉设置。我注意不到的事情一直在和他们纠缠不清[我的意思是,真的,什么傻瓜会为一个 连接池 在?但一旦他们这样做了…]而且当地面(规则)不断从你下面改变时,很难建造结构。毕竟,记住那个家伙说的关于在沼泽地建城堡的事…

        3
  •  2
  •   A-K    14 年前

    我记得不久前也遇到过类似的问题,因为JTD正在将字符串参数静默地转换为Unicode或类似的东西。转换的结果是,SQL Server无法使用从SSMS运行存储过程时使用的索引。

    缺氧缺血性脑病

        4
  •  0
  •   djna    15 年前

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

        5
  •  0
  •   Hogan    15 年前

    如果您正在查看探查器,并且执行之间没有差异,那么差异必须与客户机系统有关。

    4分钟似乎只是为了准备一个要发送的语句,所以12分钟的等待必须产生一些其他效果——不知道它是什么。

        6
  •  0
  •   James B    14 年前

    对不起,我找不到正确的答案,所以我不想把这些都分配为正确的,所以我要把这个答案标记为正确的,并祝遇到类似情况的人好运!

        7
  •  0
  •   prashant    10 年前

    我不确定这篇文章是否仍然相关。我们在应用程序中遇到了类似的问题。

    在SQL Management Studio中运行存储过程和从JDBC运行存储过程的一个关键区别是事务上下文。如果在Java中使用ORM,默认情况下,存储过程在事务上下文中运行。直接在SQL Management Studio中运行存储过程时,事务将关闭。性能差异很大。

        8
  •  -1
  •   Fortyrunner    14 年前

    你知道微软为他们的数据库提供JDBC驱动程序吗?

    这些可能更具性能。

    显然…你现在可能已经解决了这个问题。