我们使用的是SQL Server 2008 R2,它有一个很大的表(100M +行),带有主ID索引,而一datetime
列则具有非聚集索引。基于使用专门用于索引datetime列的order by
子句,我们看到了一些非常不寻常的客户端/服务器行为。
我通读了以下帖子:https : //stackoverflow.com/questions/1716798/sql-server-2008-ordering-by-datetime-is-too-slow, 但是客户端/服务器上发生的事情比实际发生的更多在这里开始描述。
如果我们运行以下查询(已编辑以保护某些内容):
select *
from [big table]
where serial_number = [some number]
order by test_date desc
查询每次都会超时。在SQL Server Profiler中,执行的查询在服务器上看起来像这样:
exec sp_cursorprepexec @p1 output,@p2 output,NULL,N'select * .....
现在,如果将查询修改为:
declare @temp int;
select * from [big table]
where serial_number = [some number]
order by test_date desc
SQL Server Profiler在服务器上显示了已执行的查询,它立即起作用:
exec sp_prepexec @p1 output, NULL, N'declare @temp int;select * from .....
实际上,您甚至可以放置一个空注释('-;')而不是未使用的声明语句,并获得相同的结果。因此,最初,我们将sp预处理程序视为此问题的根本原因,但是如果您这样做,则:
select *
from [big table]
where serial_number = [some number]
order by Cast(test_date as smalldatetime) desc
它也可以立即工作(您可以将其转换为其他任何datetime
类型),并以毫秒为单位返回结果。探查器将对服务器的请求显示为:
exec sp_cursorprepexec @p1 output, @p2 output, NULL, N'select * from .....
因此,这在一定程度上排除sp_cursorprepexec
了问题的全部原因。除此之外,sp_cursorprepexec
当不使用“ order by”时也会调用,并且结果也立即返回。
我们已经在这个问题上进行了很多搜索,我看到其他人也发布了类似的问题,但是没有一个问题可以将其分解到这个水平。
那么其他人目睹了这种行为吗?有没有人比将无意义的SQL放在select语句前面来更改行为更好的解决方案?由于SQL Server应该在收集数据后调用该命令,因此看来这是服务器中的一个已存在很长时间的错误。我们发现此行为在我们的许多大型表中都是一致的,并且是可重现的。
编辑:
我还应该添加一个forceseek
也使问题消失。
我应该添加帮助搜索者的ODBC超时错误引发为:[Microsoft] [ODBC SQL Server驱动程序]操作已取消
2012年10月12日添加:仍在寻找根本原因((已构建了要提供给Microsoft的示例,提交后,我将在此处交叉发布任何结果)。我一直在研究工作查询(带有添加的注释/声明语句)和非工作查询之间的ODBC跟踪文件。基本走线差异如下所示。在完成所有SQLBindCol讨论之后,它会在对SQLExtendedFetch的调用上发生。调用失败,返回代码为-1,然后父线程进入SQLCancel。由于我们可以使用Native Client和Legacy ODBC驱动程序来产生这种情况,因此我仍然指出服务器端存在一些兼容性问题。
(clip)
MSSQLODBCTester 1664-1718 EXIT SQLBindCol with return code 0 (SQL_SUCCESS)
HSTMT 0x001EEA10
UWORD 16
SWORD 1 <SQL_C_CHAR>
PTR 0x03259030
SQLLEN 51
SQLLEN * 0x0326B820 (0)
MSSQLODBCTester 1664-1718 ENTER SQLExtendedFetch
HSTMT 0x001EEA10
UWORD 1 <SQL_FETCH_NEXT>
SQLLEN 1
SQLULEN * 0x032677C4
UWORD * 0x032679B0
MSSQLODBCTester 1664-1fd0 ENTER SQLCancel
HSTMT 0x001EEA10
MSSQLODBCTester 1664-1718 EXIT SQLExtendedFetch with return code -1 (SQL_ERROR)
HSTMT 0x001EEA10
UWORD 1 <SQL_FETCH_NEXT>
SQLLEN 1
SQLULEN * 0x032677C4
UWORD * 0x032679B0
DIAG [S1008] [Microsoft][ODBC SQL Server Driver]Operation canceled (0)
MSSQLODBCTester 1664-1fd0 EXIT SQLCancel with return code 0 (SQL_SUCCESS)
HSTMT 0x001EEA10
MSSQLODBCTester 1664-1718 ENTER SQLErrorW
HENV 0x001E7238
HDBC 0x001E7B30
HSTMT 0x001EEA10
WCHAR * 0x08BFFC5C
SDWORD * 0x08BFFF08
WCHAR * 0x08BFF85C
SWORD 511
SWORD * 0x08BFFEE6
MSSQLODBCTester 1664-1718 EXIT SQLErrorW with return code 0 (SQL_SUCCESS)
HENV 0x001E7238
HDBC 0x001E7B30
HSTMT 0x001EEA10
WCHAR * 0x08BFFC5C [ 5] "S1008"
SDWORD * 0x08BFFF08 (0)
WCHAR * 0x08BFF85C [ 53] "[Microsoft][ODBC SQL Server Driver]Operation canceled"
SWORD 511
SWORD * 0x08BFFEE6 (53)
MSSQLODBCTester 1664-1718 ENTER SQLErrorW
HENV 0x001E7238
HDBC 0x001E7B30
HSTMT 0x001EEA10
WCHAR * 0x08BFFC5C
SDWORD * 0x08BFFF08
WCHAR * 0x08BFF85C
SWORD 511
SWORD * 0x08BFFEE6
MSSQLODBCTester 1664-1718 EXIT SQLErrorW with return code 100 (SQL_NO_DATA_FOUND)
HENV 0x001E7238
HDBC 0x001E7B30
HSTMT 0x001EEA10
WCHAR * 0x08BFFC5C
SDWORD * 0x08BFFF08
WCHAR * 0x08BFF85C
SWORD 511
SWORD * 0x08BFFEE6
(clip)
添加了Microsoft Connect案例10/12/2012:
我还应该注意,我们确实为功能查询和非功能查询查询了查询计划。它们都可以根据执行次数适当地重用。刷新缓存的计划并重新运行不会改变查询的成功。
sp_executesql
,看看会发生什么。
select id, test_date from [big table] where serial_number = ..... order by test_date
-我只是想知道这是否SELECT *
会对您的表现产生负面影响。如果您有一个非聚集索引,test_date
并且具有一个聚集索引id
(假设这就是所谓的),那么该查询应该被该非聚集索引覆盖,因此应该很快返回