Ми використовуємо SQL Server 2008 R2 і маємо дуже велику таблицю (100 М + рядків) з основним індексом ідентифікатора та 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
також називається, коли не використовується "порядок", і результат також повертається миттєво.
Ми досить гучно розглядаємо цю проблему, і я бачу подібні випуски, опубліковані від інших, але жодна, яка не підводить її до цього рівня.
Тож інші були свідками такої поведінки? Хтось має рішення краще, ніж ставити безглузді SQL перед оператором select, щоб змінити поведінку? Оскільки SQL Server повинен викликати замовлення після збору даних, то, певно, здається, що це помилка на сервері, яка зберігається тривалий час. Ми виявили, що така поведінка є послідовною у багатьох наших великих таблицях і є відтворюваною.
Зміни:
Я також повинен додати введення forceseek
також робить проблему зникає.
Мені слід додати, щоб допомогти пошуковим користувачам, викинута помилка часу очікування ODBC: [Microsoft] [ODBC Driver 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
(якщо припустити, що це називається), цей запит повинен бути охоплений цим некластеризованим індексом і, таким чином, повинен повернутися досить швидко