sql 服务器查询从 java 运行缓慢

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

我可以访问数据库来执行我想要的任何事情,但我真的不确定如何开始调试它。人们应该做些什么来弄清楚是什么导致了这样的情况?我不是一个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,并且使用响应缓冲区的默认值(已满)。更改这些属性可能有帮助吗?如果是这样,理想的设置是什么?根据我在网上找到的内容,我在想,使用直接选择方法和自适应响应缓冲可能会解决我的问题。有什么想法吗?

编辑2:

最后,我更改了这两个连接字符串参数,使用默认的选择方法(直接)并将响应缓冲区指定为自适应。这最终最适合我,并减轻了我所看到的延迟问题。谢谢你的帮助。


答案 1

我遇到了类似的问题,有一个非常简单的请求(SELECT.从。其中 = .)在 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 秒。

希望这将帮助某人!


答案 2

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

我刚刚遇到了一个类似的问题,直接在SQL Server中执行的查询需要1分钟,而通过Java准备的状态表达式,相同的查询需要5分钟。我追踪到它是作为准备好的声明完成的。

直接在 SQL Server 中执行查询时,将为其提供非参数化查询,在该查询中,它在优化时知道所有搜索条件。在我的情况下,我的搜索条件包括一个日期范围,SQL Server能够查看它,确定“该日期范围很大,让我们不要使用日期索引”,然后它选择了更好的东西。

当我通过 java 预准备语句执行同一查询时,在 SQL Server 优化查询时,您尚未向其提供任何参数值,因此它必须猜测要使用哪个索引。在我的日期范围的情况下,如果它针对小范围进行优化,并且我给它一个大范围,它将比它可能表现得更慢。同样,如果它针对大范围进行优化,而我给它一个小范围,它的性能将再次比它所能达到的要慢。

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

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

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

当然,这只有在日期范围均匀分布时才有效。如果 80% 的记录发生在去年,而 20% 的记录分布在前 10 年,那么执行“基于范围大小的多个查询”可能不是最好的。您必须根据特定范围或其他内容优化查询。你需要通过尝试一个错误来弄清楚这一点。


推荐