【问题标题】:Slow queries with preparedStatement but not with executeQuery使用preparedStatement而不是executeQuery的慢查询
【发布时间】:2017-11-26 19:26:45
【问题描述】:

我在 Grails 应用程序访问数据时遇到了一个奇怪的问题。更深入地讲,我使用 PreparedStatement.executeQuery 与 Statement.executeQuery 将问题隔离到一个普通的 java8 小型应用程序中。

考虑下面的sn-p代码:

                  
    // executes in milliseconds                  
    directSql   = "select top(10) * from vdocuments where codcli = 'CCCC' and             serial = 'SSSS' ORDER BY otherField DESC;";
    stmt = con.createStatement();
    rs = stmt.executeQuery(directSql);


    // More than 10 minutes
    sqlPrepared = "select top(10) * from vdocuments where codCli = ? and  serial = ? ORDER BY otherField DESC;";
    PreparedStatement pStatement = con.prepareStatement( sqlPrepared );
    pStatement.setString(1, "CCCC");
    pStatement.setString(2, "SSSS");
    rsPrepared = pStatement.executeQuery();

相同的查询。

数据来自 SqlServer(我认为是 2008 年,目前无法访问)的一个视图,来自一个包含超过 1500 万条记录的表。所有需要的字段都有索引,从控制台执行的相同查询(第一个)运行速度也很快。

如果我在没有 ORDER 子句的情况下执行慢速 PreparedStatement 查询,它也会运行得很快。

在我看来很清楚,无论出于何种原因,数据库都没有使用索引,并且在使用preparedStatement 时进行了全面扫描,但也许我错了,所以我愿意接受任何想法。

我想也许驱动程序(sqlserver 官方最新,jtds 已经过测试)正在保存数据,等待来自连接的任何类型的 EOF,但我已经检查了我身边的 tcpdump 并且没有收到任何数据。

我不知道为什么会这样,所以任何想法都会受到欢迎。

谢谢你!

【问题讨论】:

  • 对于性能问题,我建议的第一件事是审查执行计划。
  • 我要试一试,但是为什么这两种情况应该不同呢?最糟糕的是,我如何为preparedStatement 做这件事?据我所知,我无法从 java 执行 _EXPLAIN PLAN... _。谢谢!
  • 计划可能因数据类型不匹配或参数嗅探而不同。执行计划将揭示这一点,但一个常见问题是 Unicode 字符串参数与 varchar 列进行比较,这会阻止索引的有效使用。或者可能是由于参数嗅探,缓存的计划被重用,这对于当前参数值来说不是最佳的。
  • 您需要您的 DBA 来帮助制定计划。他们应该能够从数据库服务器上的查询缓存中提取那些。如果您有一个开发/测试环境,您有权自行执行此操作、运行跟踪等,这会容易得多。获得计划后,上传到brentozar.com/pastetheplan 并将链接添加到您的问题。跨度>
  • 感谢@danguzman 的建议(以及页面,我不知道)。我正在与一些经验丰富的数据库人员(不是我们团队中的真正 DBA,也不是客户)一起研究数据库计划,很明显,在某些情况下,SQL 使用的索引与计划的预期不同。我们无法找到原因并且需要更深入地了解知识,但看起来这可能是解决我们问题的更精确方法:blogs.msdn.microsoft.com/sqlprogrammability/2008/11/26/… 非常感谢!

标签: java sql-server jdbc


【解决方案1】:

我终于找到了解决方案,至少在我的情况下是这样。我在这里得到它http://mehmoodbluffs.blogspot.com.es/2015/03/hibernate-queries-are-slow-sql-servers.html。告诉(驱动程序?sqlServer?)不要将参数作为 Unicode 发送已经解决了这个问题。

它现在的当前连接字符串:

 String connectionUrl = "jdbc:sqlserver://server:port;databaseName=myDataBase;sendStringParametersAsUnicode=false";

现在直接查询和preparedStatements 都以毫秒的速度运行。

感谢@DanGuzman 的建议!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 2022-01-12
    • 2014-01-21
    • 2011-04-21
    相关资源
    最近更新 更多