MSSQL JDBC:加入查询性能_sometimes_非常慢

时间:2014-12-19 04:54:49

标签: sql-server jdbc

我对MSSQL数据库有一个非常奇怪的问题,其中偶尔可以接受的快速(<&lt; 0.5sec)的查询降到绝对不可接受的水平(总是大约7-8分钟)。一旦db变得如此缓慢,它将保持缓慢,直到重新启动/重新启动服务。当发生此问题时,它有时是不可预测的,有时直接在重启后,通常仅在50-100甚至更多查询之后。它似乎更常发生在两台带有Windows 8的笔记本电脑上(一台使用MSSQL Express 2k8,一台2k12),而我的开发安装在一台带有2k8 R2(内存较低,只有一个核心)的Windows 7虚拟机中,尽管它是发生在那里。

有关配置的其他事实:

客户端是Tomcat应用程序,连接配置如下 context.xml中:

<Resource name="jdbc/mydb" auth="Container" type="javax.sql.DataSource"
    maxActive="50" maxIdle="30" maxWait="10000" username="user"
    password="password" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
    url="jdbc:sqlserver://localhost:1433;DatabaseName=mydb" />

查询本身通过连接3个表(客户:32000行,100列;客户对象:47000行,140列;客户对象属性:230行,9列)选择前100行,14列,两个连接有两个条件,另外我有6个参数在5个字符串中与=进行比较,另外5个与LIKECOALESCE进行比较。结果是一个客户列表,每个客户可以有0个或更多客户对象,而每个客户对象只有这些属性中的一个。遗憾的是,没有索引,也没有明确的主键,那些应该是PK的列是字符串,就像大多数其他列一样。但这对我没有任何影响,据我所知,我认为现在没有理由影响性能,而不是总是永远

对于源所有者,我必须抽象模式和语句,但如果请求,我可以这样做。一旦我再次遇到瓶颈,执行计划也是如此。

没有其他任何东西在运行,这可能会使系统慢下来。

到目前为止,我一直在研究:

  • 在某些java版本中(无法记住哪个)mssql jdbc驱动程序有错误
  • java或mssql上的内存不应该是一个问题(MSSQL在300MB以下,java在查询执行之前/之后根本没有命中)
  • 更新了查询以使用COALESCE而不是空比较,没有关系
  • 添加TOP 100代替PreparedStatement.setMaxRows(100),没有关系
  • 将我在this语句中提取的text列中执行的语句与原始/预期语句进行比较后(一旦有错误)从SQL Management Studio尝试相同的语句,看它是否发生在这里 - 它没有
  • 尝试在窃听时解释执行计划,并与SQL Management Studio内部的执行计划进行比较 - 存在差异,但我没有经验确定什么是错误以及执行计划可能会不时出现的原因< / LI>

最后,我不得不对长篇文章说抱歉,我认为这个问题仍然导致猜测,但对我来说问题也是如此:我会理解它,如果它在某种程度上是可重复的,但我不知道到我应该看的方向。我的最后一个度假村似乎是:测试其他jdbc驱动程序或通过首先确定我想要的行而不是选择相应的值来将查询拆分为3。

亲切的问候,

基督教

PS:完全忘记提及,执行过程中根本没有java异常,只要我不打断任何内容,我会在8分钟后得到结果。

1 个答案:

答案 0 :(得分:1)

  

为什么执行计划可能会不时出现

此行为可能是由名为parameter sniffing的SQL Server功能引起的。

Erland Sommarskog有一篇关于这个主题的非常好的文章。

本质上,当您第一次运行查询时,SQL Server优化程序会生成执行计划,该计划可以使用第一次运行中实际使用的参数值进行优化。此执行计划将被缓存并重新用于此查询的将来调用。如果在查询的下一次调用中参数不同,则可能会发现缓存的执行计划不再是最佳的。事实上,它可能非常糟糕,导致执行时间过长。

一种可能的快速解决方法是将OPTION (RECOMPILE)添加到有时快速运行且有时运行缓慢的查询中。

有关此问题的详细分析和各种方法,请阅读Erland的文章。 他还解释了SET ARITHABORT在这种情况下的作用以及为什么它不是解决方案(如果问题 参数嗅探)。