14

我有一个 java 程序,它对 sql server 数据库运行一堆查询。其中第一个查询视图返回大约 750k 条记录。我可以通过 sql server management studio 运行查询,大约 30 秒就可以得到结果。但是,我昨晚启动了程序运行。当我今天早上检查它时,大约 15 个小时后,这个查询仍然没有将结果返回给 java 程序。

我可以访问数据库来做任何我想做的事情,但我真的不确定如何开始调试它。应该怎么做才能弄清楚是什么导致了这种情况?我不是 dba,对 sql server 工具集也不是很熟悉,所以如果您能提供更多关于如何执行您可能建议的操作的详细信息,我们将不胜感激。

这是代码

stmt = connection.createStatement();
clientFeedRS = stmt.executeQuery(StringBuffer.toString());

编辑1:

好吧,已经有一段时间了,这被转移了,但是这个问题又回来了。我考虑从 jdbc 驱动程序 v 1.2 升级到 2.0,但我们被困在 jdk 1.4 上,而 v 2.0 需要 jdk 1.5,所以这不是入门。现在我正在查看我的连接字符串属性。我看到 2 可能有用。

SelectMethod=cursor|direct
responseBuffering=adaptive|full

目前,由于延迟问题,我使用光标作为 selectMethod 运行,并且默认的 responseBuffering 已满。更改这些属性可能会有所帮助吗?如果是这样,理想的设置是什么?根据我在网上可以找到的内容,我在想,使用直接选择方法和自适应响应缓冲可能会解决我的问题。有什么想法吗?

编辑2:

好吧,我结束了更改这两个连接字符串参数,使用默认选择方法(直接)并将 responseBuffering 指定为自适应。这最终对我来说效果最好,并缓解了我看到的延迟问题。感谢所有的帮助。

4

13 回答 13

34

我有类似的问题,一个非常简单的请求(SELECT . FROM . WHERE = .)在Java中使用jdbc连接时最多需要10秒才能返回一行,而在sqlshell中只需要0.01秒。无论我使用的是官方的 MS SQL 驱动程序还是 JTDS 驱动程序,问题都是一样的。

解决方案是在 jdbc url 中设置此属性: sendStringParametersAsUnicode=false

如果您使用 MS SQL 官方驱动程序的完整示例:jdbc:sqlserver://yourserver;instanceName=yourInstance;databaseName=yourDBName;sendStringParametersAsUnicode=false;

如果在此处使用不同的 jdbc 驱动程序和有关该问题的更详细信息的说明:http: //emransharif.blogspot.fr/2011/07/performance-issues-with-jdbc-drivers.html

SQL Server 将支持 Unicode 的数据类型与仅支持 ASCII 的数据类型区分开来。例如,支持 Unicode 的字符数据类型是 nchar、nvarchar、longnvarchar,其中它们的 ASCII 计数器部分分别是 char、varchar 和 longvarchar。默认情况下,所有 Microsoft 的 JDBC 驱动程序都将 Unicode 格式的字符串发送到 SQL Server,而不管 SQL Server 中定义的相应列的数据类型是否支持 Unicode。在列的数据类型支持Unicode的情况下,一切都很顺利。但是,如果列的数据类型不支持 Unicode,则会出现严重的性能问题,尤其是在数据提取期间。SQL Server 在进行比较之前尝试将表中的非 unicode 数据类型转换为 unicode 数据类型。而且,如果非 unicode 列上存在索引,它将被忽略。这最终会导致在数据提取期间进行全表扫描,从而大大减慢搜索查询的速度。

就我而言,我正在搜索的表中有 30M+ 条记录。完成请求的持续时间从 10 多秒变为应用属性后大约 0.01 秒。

希望这会对某人有所帮助!

于 2015-09-30T13:36:56.957 回答
8

看来这可能不适用于您的特定情况,但我想为搜索此问题的人提供另一种可能的解释。

我刚刚遇到了类似的问题,直接在 SQL Server 中执行的查询需要 1 分钟,而通过 java 准备好的语句执行相同的查询需要 5 分钟。我追查到它是作为准备好的声明完成的。

当您直接在 SQL Server 中执行查询时,您正在为它提供一个非参数化查询,它在优化时知道所有搜索条件。就我而言,我的搜索条件包括一个日期范围,SQL Server 能够查看它,决定“那个日期范围很大,我们不要使用日期索引”,然后它选择了更好的东西。

当我通过 java 准备语句执行相同的查询时,在 SQL Server 优化查询时,您还没有提供任何参数值,因此它必须猜测要使用哪个索引。就我的日期范围而言,如果它针对一个小范围进行优化而我给它一个大范围,它的执行速度会比它可能的慢。同样,如果它针对大范围进行优化而我给它一个小范围,它的执行速度又会比它可能的慢。

为了证明这确实是问题所在,作为一个实验,我尝试提示它使用 SQL Server 的“OPTIMIZE FOR”选项优化什么。当我告诉它使用一个很小的日期范围时,我的 java 查询(实际上有一个很宽的日期范围)实际上是以前的两倍(10 分钟,而不是之前的 5 分钟,而不是 SQL Server 中的 1 分钟) )。当我告诉它我要优化的确切日期时,javaprepared 语句之间的执行时间是相同的。

所以我的解决方案是将确切的日期硬编码到查询中。这对我有用,因为这只是一次性声明。PreparedStatement 不打算被重用,而只是为了参数化值以避免 SQL 注入。由于这些日期来自 java.sql.Date 对象,我不必担心包含注入代码的日期值。

但是,对于确实需要重用的语句,硬编码日期是行不通的。也许更好的选择是创建多个针对不同日期范围优化的准备好的语句(一个针对一天,一个针对一周,一个针对一个月,一个针对一年,一个针对十年……或者也许您只需要 2 或 3 个选项...我不知道)然后对于每个查询,执行一个准备好的语句,其时间范围与实际查询中的范围最匹配。

当然,这仅在您的日期范围均匀分布时才有效。如果 80% 的记录在去年,而 20% 的记录分布在过去 10 年,那么“基于范围大小的多个查询”可能不是最好的。您必须根据特定范围或其他内容优化查询。你需要通过试错来解决这个问题。

于 2014-10-22T13:39:20.370 回答
5

确保您的 JDBC 驱动程序配置为使用直接连接而不是基于 cusror 的连接。如果您不确定,可以发布您的 JDBC 连接 URL。

确保您使用的是只进、只读的结果集(如果您没有设置它,这是默认设置)。

并确保您使用的是更新的 JDBC 驱动程序。

如果所有这些都不起作用,那么您应该查看 sql profiler 并尝试在 jdbc 驱动程序执行语句时捕获 sql 查询,并在管理工作室中运行该语句,看看是否有差异。

此外,由于您要提取如此多的数据,您应该尝试确保在 JVM 上没有任何内存/垃圾收集速度下降(尽管在这种情况下,这并不能真正解释时间差异)。

于 2009-06-07T04:18:04.460 回答
3

如果查询是参数化的,它可能是缺少参数或使用错误函数设置的参数,例如 setLong 用于字符串等。尝试使用硬编码到查询正文中的所有参数运行查询,而不会?看到这是一个问题。

于 2011-01-04T16:05:16.097 回答
2

我知道这是一个老问题,但由于它是搜索此问题时的第一个结果,我想我应该发布对我有用的内容。当我使用 SQL Server JDBC 驱动程序时,我的查询用时不到 10 秒,但在使用 jTDS 时用时超过 4 分钟。我尝试了这里提到的所有建议,但没有任何区别。唯一有效的是将其添加到 URL ";prepareSQL=1"

这里了解更多

于 2015-01-02T16:12:00.290 回答
1

我知道这是一个非常古老的问题,但由于这是搜索此问题时的第一个结果,我认为我应该发布对我有用的内容。

当我使用 SQL Server Management Studio (SSMS) 时,我有一个查询大约需要 3 秒,但通过该executeQuery方法使用 jTDS JDBC 驱动程序运行时需要 3.5 分钟。

上面提到的建议都没有对我有用,主要是因为我只使用了 Statement 而不是 Prepared Statement。唯一对我有用的是在连接字符串中指定初始或默认数据库的名称,连接用户至少具有db_datareader数据库角色成员资格。仅有公共角色是不够的。

这是示例连接字符串:

jdbc:jtds:sqlserver://YourSqlServer.name:1433/DefaultDbName

Please ensure that you have the ending /DefaultDbName specified in the connection string. Here DefaultDbName is the name of the database to which the user ID specified for making the JDBC connection has at least the db_datareader database role. If omitted, SQL Server defaults to using the master database. If the user ID used to make the JDBC connection only has the public role in the master database, the query takes exceptionally long.

I don’t know why this happens. However, I know a different query plan is used in such circumstances. I confirmed this using the SQL Profiler tool.

Environment details:

  • SQL Server version: 2016
  • jTDS driver version: 1.3.1
  • Java version: 11
于 2019-02-27T23:47:24.177 回答
0

撤回这么多数据将需要大量时间。您可能应该想办法在任何给定时间在您的应用程序中不需要那么多数据。例如,分页数据或使用延迟加载。如果没有关于您要完成的工作的更多细节,很难说。

于 2009-06-07T02:43:26.750 回答
0

从管理工作室运行时它很快的事实可能是由于不正确的缓存查询计划和过时的索引(例如,由于大量导入或删除)。它是否在 SSMS 中快速返回所有 750K 记录?

尝试重建您的索引(或者如果这需要太长时间,请更新您的统计信息);并且可能刷新过程缓存(如果这是一个生产系统,请谨慎使用......):DBCC FREEPROCCACHE

于 2009-06-07T02:53:49.770 回答
0

要开始调试,最好确定问题区域是在数据库中还是在应用程序中。您是否尝试过更改查询以使其返回更小的结果?如果那没有返回,我建议针对您从 Java 访问数据库的方式。

于 2009-06-07T03:53:42.900 回答
0

尝试调整Statement的fetch size,尝试cursor的selectMethod

http://technet.microsoft.com/en-us/library/aa342344(SQL.90).aspx

我们在使用 mysql 时遇到了大型结果集的问题,需要使其流式传输结果集,如以下链接中所述。

http://helpdesk.objects.com.au/java/avoiding-outofmemoryerror-with-mysql-jdbc-driver

于 2009-06-07T04:20:09.950 回答
0

引用自 MS 自适应缓冲区指南:

避免使用连接字符串属性 selectMethod=cursor 以允许应用程序处理非常大的结果集。自适应缓冲功能允许应用程序在不使用服务器游标的情况下处理非常大的只进、只读结果集。请注意,当您设置 selectMethod=cursor 时,该连接生成的所有只进、只读结果集都会受到影响。换句话说,如果您的应用程序经常处理包含几行的短结果集,那么为每个结果集创建、读取和关闭服务器游标将在客户端和服务器端使用比使用 selectMethod 的情况更多的资源未设置为光标。

在某些情况下,使用 selectMethod=cursor 而不是 responseBuffering=adaptive 会更有益,例如:

  • 如果您的应用程序处理只进、只读的结果集很慢,例如在某些用户输入后读取每一行,使用 selectMethod=cursor 而不是 responseBuffering=adaptive 可能有助于减少 SQL Server 的资源使用。

  • 如果您的应用程序在同一连接上同时处理两个或更多只进、只读结果集,则使用 selectMethod=cursor 而不是 responseBuffering=adaptive 可能有助于减少驱动程序在处理这些结果集时所需的内存。

在这两种情况下,您都需要考虑创建、读取和关闭服务器游标的开销。

查看更多:http ://technet.microsoft.com/en-us/library/bb879937.aspx

于 2013-03-13T09:37:09.913 回答
0

有时可能是由于参数绑定到查询对象的方式。从java程序执行时,我发现以下代码非常慢。

Query query = em().createNativeQuery(queryString)                    
                .setParameter("param", SomeEnum.DELETED.name())

一旦我删除了“deleted”参数并直接将该“DELETED”字符串附加到查询中,它变得非常快。这可能是因为 SQL Server 期望绑定所有参数来决定优化计划。

于 2018-02-08T03:02:15.043 回答
-1

SQLWB 是否需要类似的时间?如果 Java 版本慢得多,那么我会检查几件事:

  1. 您应该使用只进、只读的 ResultSet 获得最佳性能。
  2. 我记得 MSFT 的旧 JDBC 驱动程序很慢。确保您使用的是最新的 n-greatest。我认为有一个通用的 SQL Server 一个和一个专门用于 SQL 2005。
于 2009-06-07T03:53:54.117 回答