Stiamo utilizzando SQL Server 2008 R2 e disponiamo di una tabella (100 M + righe) molto grande con un indice ID primario e una datetime
colonna con un indice non cluster. Stiamo riscontrando alcuni comportamenti client / server molto insoliti basati sull'uso di una order by
clausola specificamente su una colonna di data / ora indicizzata .
Ho letto il seguente post: /programming/1716798/sql-server-2008-ordering-by-datetime-is-too-slow ma c'è molto di più nel client / server di quello che è iniziare descritto qui.
Se eseguiamo la seguente query (modificata per proteggere alcuni contenuti):
select *
from [big table]
where serial_number = [some number]
order by test_date desc
La query scade ogni volta. In SQL Server Profiler la query eseguita appare così al server:
exec sp_cursorprepexec @p1 output,@p2 output,NULL,N'select * .....
Ora se modifichi la query in, dì questo:
declare @temp int;
select * from [big table]
where serial_number = [some number]
order by test_date desc
SQL Server Profiler mostra che la query eseguita è simile al server e FUNZIONA all'istante:
exec sp_prepexec @p1 output, NULL, N'declare @temp int;select * from .....
È un dato di fatto, puoi anche inserire un commento vuoto ('-;') invece di un'istruzione dichiarare inutilizzata e ottenere lo stesso risultato. Quindi inizialmente stavamo puntando al pre-processore sp come causa principale di questo problema, ma se lo fai:
select *
from [big table]
where serial_number = [some number]
order by Cast(test_date as smalldatetime) desc
Funziona anche all'istante (puoi lanciarlo come qualsiasi altro datetime
tipo), restituendo il risultato in millisecondi. E il profiler mostra la richiesta al server come:
exec sp_cursorprepexec @p1 output, @p2 output, NULL, N'select * from .....
In tal modo si esclude in qualche modo la sp_cursorprepexec
procedura dalla piena causa del problema. Aggiungete a ciò il fatto che sp_cursorprepexec
viene anche chiamato quando non viene utilizzato 'ordina per' e il risultato viene restituito istantaneamente.
Abbiamo cercato su Google per questo problema un bel po ', e vedo problemi simili pubblicati da altri, ma nessuno che lo divide a questo livello.
Quindi altri hanno assistito a questo comportamento? Qualcuno ha una soluzione migliore del mettere SQL senza senso davanti all'istruzione select per cambiare il comportamento? Dato che SQL Server dovrebbe invocare l'ordine dopo che i dati sono stati raccolti, sembra che si tratti di un bug nel server che persiste da molto tempo. Abbiamo riscontrato che questo comportamento è coerente su molte delle nostre tabelle di grandi dimensioni ed è riproducibile.
modifiche:
Dovrei anche aggiungere un inserimento per far forceseek
scomparire il problema.
Dovrei aggiungere per aiutare i ricercatori, l'errore di timeout ODBC generato è: [Microsoft] [Driver ODBC SQL Server] Operazione annullata
Aggiunto il 10/12/2012: Continuo a cercare la causa principale (oltre a aver creato un campione da dare a Microsoft, inserirò qui tutti i risultati dopo averlo inviato). Ho scavato nel file di traccia ODBC tra una query funzionante (con un commento aggiunto / dichiarazione dichiarazione) e una query non funzionante. La differenza di traccia fondamentale è pubblicata di seguito. Si verifica sulla chiamata alla chiamata SQLExtendedFetch al termine di tutte le discussioni di SQLBindCol. La chiamata ha esito negativo con il codice di ritorno -1 e il thread padre immette quindi SQLCancel. Dato che siamo in grado di produrlo con entrambi i driver ODBC Native Client e Legacy, sto ancora indicando un problema di compatibilità sul lato server.
(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)
Aggiunto un caso Microsoft Connect del 10/12/2012:
Dovrei anche notare che abbiamo cercato i piani di query sia per le query funzionanti che non funzionanti. Entrambi vengono riutilizzati in modo appropriato in base al conteggio delle esecuzioni. Lo svuotamento dei piani memorizzati nella cache e la riesecuzione non modificano il successo della query.
sp_executesql
e guarda cosa succede.
select id, test_date from [big table] where serial_number = ..... order by test_date
- mi chiedo solo se ciòSELECT *
abbia un impatto negativo sulla tua performance. Se hai un indice non cluster attivatotest_date
e un indice cluster attivatoid
(supponendo che sia quello che viene chiamato), questa query dovrebbe essere coperta da quell'indice non cluster e quindi dovrebbe restituire abbastanza rapidamente