Мы используем SQL Server 2008 R2, и у нас есть очень большая (100M + строки) таблица с индексом первичного идентификатора и datetime
столбец с некластеризованным индексом. Мы наблюдаем довольно необычное поведение клиент / сервер, основанное на использовании order by
предложения специально для индексированного столбца даты и времени .
Я прочитал следующий пост: /programming/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 показывает, что выполненный запрос выглядит на сервере следующим образом, и он работает мгновенно:
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] Операция отменена
Добавлено 12.10.2012: Все еще выискивая основную причину (наряду с созданием образца для передачи в Microsoft, я буду отправлять здесь любые результаты после отправки). Я копался в файле трассировки ODBC между рабочим запросом (с добавленным оператором комментария / объявления) и нерабочим запросом. Фундаментальная разница трасс приведена ниже. Это происходит при вызове вызова SQLExtendedFetch после завершения всех обсуждений SQLBindCol. Вызов завершается неудачно с кодом возврата -1, и родительский поток затем вводит SQLCancel. Так как мы можем производить это как с Native Client, так и с устаревшими драйверами 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
(при условии, что он так и называется), этот запрос должен быть покрыт этим некластеризованным индексом и, следовательно, должен возвращаться довольно быстро