Wir verwenden SQL Server 2008 R2 und haben eine sehr große Tabelle (über 100 datetime
Millionen Zeilen) mit einem primären ID-Index und eine Spalte mit einem nicht gruppierten Index. Wir sehen ein sehr ungewöhnliches Client / Server-Verhalten, das auf der Verwendung einer order by
Klausel speziell für eine indizierte Datetime-Spalte basiert .
Ich habe den folgenden Beitrag gelesen: /programming/1716798/sql-server-2008-ordering-by-datetime-is-too-slow, aber mit dem Client / Server ist mehr los als das, was ist beginnen hier beschrieben.
Wenn wir die folgende Abfrage ausführen (bearbeitet, um einige Inhalte zu schützen):
select *
from [big table]
where serial_number = [some number]
order by test_date desc
Die Abfrage läuft jedes Mal ab. Im SQL Server Profiler sieht die ausgeführte Abfrage für den Server folgendermaßen aus:
exec sp_cursorprepexec @p1 output,@p2 output,NULL,N'select * .....
Wenn Sie nun die Abfrage ändern, sagen Sie Folgendes:
declare @temp int;
select * from [big table]
where serial_number = [some number]
order by test_date desc
Der SQL Server-Profiler zeigt an, dass die ausgeführte Abfrage für den Server folgendermaßen aussieht und sofort FUNKTIONIERT:
exec sp_prepexec @p1 output, NULL, N'declare @temp int;select * from .....
Tatsächlich können Sie anstelle einer nicht verwendeten Deklarationsanweisung sogar einen leeren Kommentar ('-;') einfügen und das gleiche Ergebnis erzielen. Daher haben wir anfangs auf den SP-Vorprozessor als Hauptursache für dieses Problem hingewiesen, aber wenn Sie dies tun:
select *
from [big table]
where serial_number = [some number]
order by Cast(test_date as smalldatetime) desc
Es funktioniert auch sofort (Sie können es wie jeden anderen datetime
Typ umwandeln) und gibt das Ergebnis in Millisekunden zurück. Der Profiler zeigt die Anforderung an den Server wie folgt an:
exec sp_cursorprepexec @p1 output, @p2 output, NULL, N'select * from .....
Damit wird das sp_cursorprepexec
Verfahren etwas von der vollständigen Ursache des Problems ausgeschlossen. Hinzu kommt, dass das sp_cursorprepexec
auch aufgerufen wird, wenn keine 'order by' verwendet wird, und das Ergebnis auch sofort zurückgegeben wird.
Wir haben ziemlich viel nach diesem Problem gegoogelt, und ich sehe ähnliche Probleme von anderen, aber keine, die es auf dieses Niveau herunterbrechen.
Haben andere dieses Verhalten gesehen? Hat jemand eine bessere Lösung, als bedeutungsloses SQL vor die select-Anweisung zu stellen, um das Verhalten zu ändern? Da SQL Server die Reihenfolge nach dem Sammeln der Daten aufrufen sollte, scheint dies ein Fehler auf dem Server zu sein, der lange Zeit bestehen geblieben ist. Wir haben festgestellt, dass dieses Verhalten in vielen unserer großen Tabellen konsistent und reproduzierbar ist.
Bearbeitungen:
Ich sollte auch hinzufügen, forceseek
dass durch das Einfügen auch das Problem verschwindet.
Ich sollte hinzufügen, um den Suchenden zu helfen. Der ODBC-Timeout-Fehler lautet: [Microsoft] [ODBC SQL Server-Treiber] Vorgang abgebrochen
Hinzugefügt am 12.10.2012: Ich bin immer noch auf der Suche nach der Grundursache (zusammen mit der Erstellung eines Beispiels für Microsoft werde ich hier alle Ergebnisse veröffentlichen, nachdem ich sie eingereicht habe). Ich habe in der ODBC-Tracedatei zwischen einer funktionierenden Abfrage (mit einem hinzugefügten Kommentar / einer Deklarationsanweisung) und einer nicht funktionierenden Abfrage gesucht. Der grundlegende Trace-Unterschied ist unten angegeben. Es tritt beim Aufruf von SQLExtendedFetch auf, nachdem alle SQLBindCol-Diskussionen abgeschlossen sind. Der Aufruf schlägt mit dem Rückkehrcode -1 fehl und der übergeordnete Thread gibt dann SQLCancel ein. Da wir dies sowohl mit dem Native Client- als auch mit dem Legacy-ODBC-Treiber erstellen können, weise ich immer noch auf ein Kompatibilitätsproblem auf der Serverseite hin.
(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-Fall 10/12/2012 hinzugefügt:
Ich sollte auch beachten, dass wir die Abfragepläne sowohl für funktionierende als auch für nicht funktionierende Abfragen nachgeschlagen haben. Sie werden beide entsprechend der Ausführungsanzahl entsprechend wiederverwendet. Das Leeren der zwischengespeicherten Pläne und das erneute Ausführen ändern nichts am Erfolg der Abfrage.
sp_executesql
und sehen Sie, was passiert.
select id, test_date from [big table] where serial_number = ..... order by test_date
Ich frage mich nur, obSELECT *
sich dies negativ auf Ihre Leistung auswirkt. Wenn Sie einen nicht gruppierten Index auf habentest_date
und einen Clustered - Index aufid
(das ist vorausgesetzt , was es heißt), diese Abfrage sollte werden abgedeckt durch diese nicht gruppierten Index und sollte daher recht schnell wieder