Sql server 为什么针对MSSQL 2008SP2的ODBC查询所需的时间是Studio中相同查询的100倍?

Sql server 为什么针对MSSQL 2008SP2的ODBC查询所需的时间是Studio中相同查询的100倍?,sql-server,database,Sql Server,Database,我有一个非常奇怪的查询,涉及到一个复杂视图的连接。我分析了这个视图,构建了一些索引,并在从MSSQL Management Studio运行时在一秒钟内完成了查询。然而,当通过ODBC从Perl运行时,返回完全相同的查询大约需要80秒 我已经花了将近8个小时在这件事上,它继续困扰着我。在这段时间里,我从Perl记录了查询,并将其逐字复制到Studio中,我将其包装在一个存储过程中(这使两个客户机的查询时间一致为2.5分钟!),我在谷歌上搜索了ODBC和MSSQL查询缓存,我通过活动监视器观看了查

我有一个非常奇怪的查询,涉及到一个复杂视图的连接。我分析了这个视图,构建了一些索引,并在从MSSQL Management Studio运行时在一秒钟内完成了查询。然而,当通过ODBC从Perl运行时,返回完全相同的查询大约需要80秒

我已经花了将近8个小时在这件事上,它继续困扰着我。在这段时间里,我从Perl记录了查询,并将其逐字复制到Studio中,我将其包装在一个存储过程中(这使两个客户机的查询时间一致为2.5分钟!),我在谷歌上搜索了ODBC和MSSQL查询缓存,我通过活动监视器观看了查询的运行(它大部分时间都处于一般的睡眠任务等待状态)和Profiler(select语句得到一行,直到它运行完毕才显示出来),我已经开始阅读性能瓶颈

我没有注意到来自Perl的任何其他查询存在这个问题,不幸的是,我们现场没有DBA。我是一个程序员,做过一些DBA,但我觉得我在黑暗中摸索这一个。我最好的猜测是,Studio中有某种查询缓存是ODBC客户端无法访问的,但是重新启动Studio不会使查询的第一次执行花费更长的时间,所以看起来不像是因为每个新的ODBC连接都以空缓存开始

无需进入视图定义,基本查询非常简单:

SELECT * FROM VIEW1 LEFT OUTER JOIN VIEW2 WHERE SECTION = ? AND ID = ?
当我放下VIEW2时,延迟消失了,但我需要该视图中的数据。为了简化和提高效率,我已经重写了三次视图,但这感觉有点像死胡同,因为查询在Studio中运行良好。查询只返回一行,但即使删除ID条件并为整个部分选择所有56k行,从Studio只需40秒。还有其他想法吗

编辑2/8: @Remus Rusanu链接的文章非常清楚,但我担心它不太适用。现在看来很明显,这根本不是ODBC,但当我硬编码参数与参数化参数时,我会得到不同的执行计划。我可以在SSMS中重现这一点:

SELECT * FROM VIEW1 LEFT OUTER JOIN VIEW2 WHERE SECTION = 'a' AND ID = 'b'
它的速度是它的100倍

DECLARE @p1 VARCHAR(8), @p2 VARCHAR(3)
SET @p1 = 'a'
SET @p2 = 'b'
SELECT * FROM VIEW1 LEFT OUTER JOIN VIEW2 WHERE SECTION = @p1 AND ID = @p2
不幸的是,对于SECTION&ID的任何值,我仍然无法解释为什么第一个应该得到比参数化版本少两个数量级时间的执行计划。这可能是SQL Server中的一个缺陷,但输入在两个地方都是已知的,而其中一个却需要更长的时间,这似乎很愚蠢。如果SQL server每次都从头开始重新计算参数化计划,就像它必须对我提供的不同常量值所做的那样,速度会快100倍。文章中建议的任何重新编译选项似乎都没有帮助

我想@GSerg是在下面说的。我还没有证明在视图外部使用窗口函数时不会发生这种情况,但他描述了同样的事情,并且时间差异仍然令人困惑


如果我没有时间来处理这个问题,我会尝试修改文章中的一些建议,并在参数化版本上强制执行持续执行计划,但似乎有很多不必要的麻烦。

关于这个主题,你想知道的一切:


SSMS中没有ODBC无法访问的“缓存”。只是由于参数嗅探或数据类型优先规则,SSMS和ODBC中的执行计划不同。阅读链接的文章,它既有识别问题的方法,也有解决问题的建议

比较这两个查询的计划,并检查每个连接的
SET
设置(您可以通过查看sys.dm\u exec\u会话来完成此操作)。我敢打赌,你会发现引号中的标识符、ansi_null或arithabort(或者可能全部三个)会有所不同。这通常会导致执行计划的巨大差异。您应该能够在ODBC版本中手动设置这些设置,以便与Management Studio使用的设置相匹配

一些相关问题-可能还有其他一些模糊的情况,您需要检查:

到目前为止,这是SQL Server中的一个问题,尚未完全解决

正如链接问题的答案和评论中所建议的,您可以

  • 将查询包装成附加
    选项(重新编译)
  • 将其转换为表值函数
  • 使用
    选项(重新编译)

您是否碰巧在该视图中获得了依赖于
部分或
id
的窗口功能?例如
rank()over(partitionby section)
。删除视图时,延迟会消失,因为您无法再查询视图-它会立即返回,并出现无效的对象错误。只是说,是的。我在两者上都使用了一个窗口函数:ROW_NUMBER()over(PARTITION BY SECTION,ID)@DerekP我在一些测试之前和之后都遇到了一个非常类似的问题,只能断定这是SQL Server 2008中的一个bug。当使用参数时,依赖于外部附加到视图的
条件的窗口函数会导致提取所有行,计算所有可能组合的所有窗口,然后过滤,这是荒谬的。如果
where
caluse用文字值表示,则不会发生这种情况。从视图中删除
行编号()。如果需要,从调用查询外部应用它。@DerekP当包装在过程中时,您的意思是查询在两个客户端之间的时间为2.5分钟。就是这样。您是通过将文字数字放入查询字符串来执行来自SSMS的查询的,不是吗?例如
其中section=1和id=2
,而不是
其中section=@section a