sql server查询从java运行缓慢

问题描述 投票:9回答:13

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

我可以访问数据库来执行我想要的任何操作,但我真的不确定如何开始调试它。应该怎么做才能找出造成这种情况的原因?我不是一个dba,并且我对sql server工具集并不是很熟悉,所以你可以给我更多关于如何做你可能建议的内容的细节将不胜感激。

继承人的代码

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

EDIT1

好吧已经有一段时间了,而且这种情况有所不同,但这个问题又回来了。我考虑从jdbc驱动程序v 1.2升级到2.0,但是我们仍然坚持使用jdk 1.4,而v 2.0需要jdk 1.5,所以这是一个非首发。现在我正在查看我的连接字符串属性。我看到2可能有用。

SelectMethod=cursor|direct
responseBuffering=adaptive|full

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

Aaditi:

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

java sql-server-2005 jdbc connection-string
13个回答
4
投票

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

确保您使用的是只进,只读结果集(如果您未设置,则这是默认设置)。

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

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

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


0
投票

引用MS Adaptive缓冲区指南:

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

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

  • 如果您的应用程序缓慢处理只进,只读结果集,例如在某些用户输入后读取每一行,则使用selectMethod = cursor而不是responseBuffering = adaptive可能有助于减少SQL Server的资源使用。
  • 如果您的应用程序在同一连接上同时处理两个或多个只进,只读结果集,则使用selectMethod = cursor而不是responseBuffering = adaptive可能有助于减少驱动程序在处理这些结果集时所需的内存。

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

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


0
投票

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

http://technet.microsoft.com/en-us/library/bb879937.aspx

一旦我删除“已删除”参数并直接将“删除”字符串附加到查询,它就变得非常快。这可能是由于SQL服务器期望绑定所有参数来决定优化计划。


0
投票

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

当我使用SQL Server Management Studio(SSMS)时,我的查询花了大约3秒钟,但是当通过Query query = em().createNativeQuery(queryString) .setParameter("param", SomeEnum.DELETED.name()) 方法使用jTDS JDBC驱动程序运行时花了3.5分钟。

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

这是示例连接字符串:

executeQuery

请确保您在连接字符串中指定了结尾jdbc:jtds:sqlserver://YourSqlServer.name:1433/DefaultDbName 。这里/DefaultDbName是为建立JDBC连接而指定的用户标识至少具有DefaultDbName数据库角色的数据库的名称。如果省略,SQL Server默认使用db_datareader数据库。如果用于建立JDBC连接的用户标识仅在master数据库中具有master角色,则查询需要特别长的时间。

我不知道为什么会这样。但是,我知道在这种情况下使用不同的查询计划。我使用SQL Profiler工具确认了这一点。

环境细节:

  • SQL Server版本:2016
  • jTDS驱动程序版本:1.3.1
  • Java版本:11

-1
投票

SQLWB需要花费相似的时间吗?如果Java版本慢得多,那么我会检查几件事:

  1. 您应该使用只进,只读ResultSet获得最佳性能。
  2. 我记得MSFT的旧JDBC驱动程序很慢。确保您使用的是最新的n-great。我认为有一个通用的SQL Server,一个专门用于SQL 2005。

22
投票

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

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

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

如果使用不同的jdbc驱动程序和更多有关此问题的详细信息,请参阅:qazxsw poi

SQL Server将支持Unicode的数据类型与仅支持ASCII的数据类型区分开来。例如,支持Unicode的字符数据类型是nc​​har,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秒。

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


7
投票

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

我只是遇到了类似的问题,在SQL Server中直接执行查询需要1分钟,而同一查询通过java编写的statemnent需要5分钟。我追踪到它是作为准备好的声明完成的事实。

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

当我通过java预处理语句执行相同的查询时,在SQL Server优化查询时,您还没有提供任何参数值,因此它必须猜测要使用哪个索引。在我的日期范围的情况下,如果它优化了小范围并且我给它一个大范围,它将执行比它可能更慢。同样地,如果它针对大范围进行优化并且我给它一个小范围,那么它将再次执行得比它慢。

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

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

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

当然,这只适用于日期范围均匀分布的情况。如果80%的记录是去年的,而20%的记录分布在过去的10年中,那么做“基于范围大小的多个查询”的事情可能不是最好的。您必须根据特定范围或某些内容优化查询。你需要通过试验找出错误。


3
投票

如果查询是参数化的,则它可以是缺失参数或用错误函数设置的参数,例如, setLong for string等。尝试使用硬编码到查询体中的所有参数运行您的查询,而不需要任何http://emransharif.blogspot.fr/2011/07/performance-issues-with-jdbc-drivers.html来查看这是一个问题。


1
投票

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

有关更多信息,请参阅?


0
投票

拉回那么多数据需要很多时间。您应该想办法在任何给定时间不要求应用程序中有太多数据。例如,页面数据或使用Here。如果没有关于你想要完成什么的更多细节,很难说。


0
投票

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

尝试重建索引(如果这需要太长时间,请更新统计信息);并且可能会刷新过程缓存(如果这是一个生产系统,请小心......):lazy loading


0
投票

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


0
投票

尝试调整Statement的获取大小并尝试selectMethod of cursor

DBCC FREEPROCCACHE

我们遇到了使用mysql的大型结果集的问题,并且需要使其按照以下链接中的说明对结果集进行流式处理。

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

© www.soinside.com 2019 - 2024. All rights reserved.