【发布时间】: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