Nous utilisons SQL Server 2008 R2 et avons une très grande table (100M + lignes) avec un index d'ID principal et une datetimecolonne avec un index non cluster. Nous constatons un comportement client / serveur très inhabituel basé sur l'utilisation d'une order byclause spécifiquement sur une colonne datetime indexée .
J'ai lu l'article suivant: /programming/1716798/sql-server-2008-ordering-by-datetime-is-too-slow mais il se passe plus de choses avec le client / serveur que ce qui est commencer décrit ici.
Si nous exécutons la requête suivante (modifiée pour protéger certains contenus):
select *
from [big table]
where serial_number = [some number]
order by test_date desc
La requête expire à chaque fois. Dans le SQL Server Profiler, la requête exécutée ressemble à ceci au serveur:
exec sp_cursorprepexec @p1 output,@p2 output,NULL,N'select * .....
Maintenant, si vous modifiez la requête en, dites ceci:
declare @temp int;
select * from [big table]
where serial_number = [some number]
order by test_date desc
Le SQL Server Profiler montre la requête exécutée comme ceci au serveur, et cela FONCTIONNE instantanément:
exec sp_prepexec @p1 output, NULL, N'declare @temp int;select * from .....
En fait, vous pouvez même mettre un commentaire vide ('-;') au lieu d'une instruction declare inutilisée et obtenir le même résultat. Donc, au départ, nous pointions le préprocesseur sp comme cause première de ce problème, mais si vous faites cela:
select *
from [big table]
where serial_number = [some number]
order by Cast(test_date as smalldatetime) desc
Il fonctionne également instantanément (vous pouvez le lancer comme n'importe quel autre datetimetype), retournant le résultat en millisecondes. Et le profileur affiche la demande au serveur sous la forme:
exec sp_cursorprepexec @p1 output, @p2 output, NULL, N'select * from .....
Cela exclut donc quelque peu la sp_cursorprepexecprocédure de la cause complète du problème. Ajoutez à cela le fait que le sp_cursorprepexecest également appelé lorsqu'aucune commande par n'est utilisée et le résultat est également retourné instantanément.
Nous avons beaucoup cherché sur ce problème, et je vois des problèmes similaires publiés par d'autres, mais aucun qui le décompose à ce niveau.
Les autres ont-ils donc été témoins de ce comportement? Quelqu'un a-t-il une meilleure solution que de mettre du SQL vide de sens devant l'instruction select pour changer le comportement? Étant donné que SQL Server doit invoquer la commande après la collecte des données, il semble bien que ce soit un bogue sur le serveur qui persiste depuis longtemps. Nous avons constaté que ce comportement est cohérent dans plusieurs de nos grandes tables et qu'il est reproductible.
Modifications:
Je dois également ajouter que la mise forceseeken place fait également disparaître le problème.
Je devrais ajouter pour aider les chercheurs, l'erreur de délai d'expiration ODBC levée est: [Microsoft] [Pilote ODBC SQL Server] Opération annulée
Ajouté le 12/12/2012: Toujours à la recherche de la cause première (en plus d'avoir construit un échantillon à donner à Microsoft, je posterai les résultats ici après avoir soumis) J'ai creusé dans le fichier de trace ODBC entre une requête de travail (avec une déclaration de commentaire / déclaration ajoutée) et une requête qui ne fonctionne pas. La différence de trace fondamentale est affichée ci-dessous. Il se produit lors de l'appel à l'appel SQLExtendedFetch une fois toutes les discussions SQLBindCol terminées. L'appel échoue avec le code retour -1, et le thread parent entre ensuite dans SQLCancel. Étant donné que nous pouvons produire cela avec les pilotes ODBC client natif et hérité, je signale toujours un problème de compatibilité côté serveur.
(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)
Ajout d'un cas Microsoft Connect 10/12/2012:
Je dois également noter que nous avons recherché les plans de requête pour les requêtes fonctionnelles et non fonctionnelles. Ils sont tous deux réutilisés de manière appropriée en fonction du nombre d'exécutions. Le vidage des plans mis en cache et la réexécution ne modifient pas le succès de la requête.
sp_executesqlet voyez ce qui se passe.
select id, test_date from [big table] where serial_number = ..... order by test_date- je me demande simplement si celaSELECT *a un impact négatif sur vos performances. Si vous avez un index non clusterisétest_dateet un index clusteriséid(en supposant que c'est ainsi qu'on l'appelle), cette requête devrait être couverte par cet index non clusterisé et devrait donc revenir assez rapidement