Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

SQL Server : Conserver la date ou l’heure d’un datetime (Comparaison des méthodes)

Les types dates de SQL Server, comportent toujours la date et l'heure alors que souvent nous ne souhaitons utiliser que l'un ou l'autre. Dans ce genre de situation nous « resetons » manuellement l'un ou l'autre partie qui ne intéresse pas.

Tout d'abord comment ne conserver que la partie date, cette liste et non limitative, et vous pourrez peut être trouver mieux en terme de perf.

SELECT CONVERT(datetime, CONVERT(char(10), X, 103), 103) FROM DateTable -- 18.5 sec
SELECT DATEADD(d, 0, FLOOR(CAST(X as float))) FROM DateTable -- 7.5 sec
SELECT CAST(FLOOR(CAST(X as float)) as datetime) FROM DateTable -- 6.3 sec
SELECT CAST(CAST(CAST(X as float) as int) as datetime) FROM DateTable -- 4.5 sec

-- Les conversions qui suivent ne fonctionnent pas à cause de l'arrondi
SELECT DATEADD(d, 0, CAST(X as int)) FROM DateTable -- 4.9 sec
SELECT CAST(CAST(X as int) as datetime) FROM DateTable -- 4.0 sec

X représente le champ date à convertir, DateTable contient environ 19 millions de dates (date et heure) pour effectuer les tests. Le temps indiqué derrière correspond au temps CPU approximatif consommé par la requête (sur ma machine).

La première méthode est la plus lente, elle repose sur CONVERT qui permet contrairement à CAST de passer le format souhaité de date. On a choisit le format 103 qui correspond à JJ/MM/AAAA c'est-à-dire le format utilisé en France. Ce format n'indique pas l'heure et qui permet en effectuant 2 CONVERT successif d'obtenir uniquement la date avec l'heure à minuit.

La seconde repose sur une conversion de date en float, un arrondit du float et une reconversion en datetime. Le gain est très net par rapports aux fonctions de date utilisé pour le premier exemple. Cette méthode je l'ai découverte grâce à Nix, ici.

Partons de cette méthode pour aller plus vite. Clairement l'arrondi du float est en trop, on peut réaliser la conversion directement en int. Quant au DATEADD il ne fait qu'une reconversion du int en datetime donc autant refaire un CAST en datetime à la place. Le problème comme l'a fait remarquer Nicolas en commentaire c'est que ces méthodes revoient un résultat faux à cause de l'arrondi produit par le CAST datetime vers int. Avec le DATEADD remplacé par un CAST on gagne une seconde de temps CPU. Et le FLOOR est remplacé par un CAST, le CAST d'un float vers int effectue une troncation des décimales, ce qui est l'effet souhaité chez nous.

Il n'y a pas de différence de performance entre l'utilisation du CONVERT ou du CAST, je préfère le CAST celui-ci étant un standard SQL. Le comportement de toutes les méthodes citées plus haut est identique pour un datetime et smalldatetime.

Maintenant pour conserver la composante heure d'un datetime.

SELECT CONVERT(datetime, CONVERT(char(10), X, 114), 114) FROM DateTable – 18.9 sec
SELECT CAST(CAST(X as binary(4)) as datetime) FROM DateTable – 5.7 sec

La première est la copie conforme de la première utilisée pour la partie date, elle d'ailleurs tout aussi rapide :o>

La seconde méthode convertit la date en binary(4) ce qui a pour effet de tronquer la partie date pour un datetime. Pour un smalldatetime il faudra convertir en binary(2) pour obtenir le même effet.

Si vous trouvez mieux et plus rapide postez un commentaire sur cette page. Merci :o)

Bon dev…

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Publié dimanche 29 avril 2007 10:00 par christian
Classé sous : ,

Commentaires

dimanche 29 avril 2007 11:24 by nletullier

# re: SQL Server : Conserver la date ou l’heure d’un datetime (Comparaison des méthodes)

Bonjour,

Intéressant, mais je noterais un "petit", voire un gros souci dans ces solutions. En effet, le CAST(ChampDate AS INT) ne fait pas une troncature de la partie décimale, mais un arrondi. Ce qui fait que toutes les solutions proposées qui utilisent un CAST en INT ne sont bonnes que pour les heures avant midi.

La solution consiste à faire, non pas un CAST en INT, mais le FLOOR d'un CAST en FLOAT.

Démonstration :

SET STATISTICS TIME ON

DECLARE @ladate DATETIME

SELECT @ladate = CONVERT(datetime, '03/16/2006 13:01')

SELECT @ladate,

CAST(FLOOR(CAST(@ladate AS float))  AS datetime) AS CastEnFloat,

DATEADD(d, 0, CAST(@ladate  as int)) AS DateAddSurCastEnInt,

CAST(CAST(@ladate AS int) AS datetime) CastEnInt,

CONVERT(datetime, CONVERT(char(10), @ladate, 103), 103) AS DoubleConvert

Nicolas.

dimanche 29 avril 2007 12:52 by christian

# re: SQL Server : Conserver la date ou l’heure d’un datetime (Comparaison des méthodes)

Merci d'avoir remarqué la boulette :o)

lundi 30 avril 2007 21:32 by Nix

# re: SQL Server : Conserver la date ou l’heure d’un datetime (Comparaison des méthodes)

Pourtant j'avais bien mi "float" dans mon exemple :p

http://www.sqlfr.com/codes/FAIRE-COUNT-GROUPER-DATE-AVEC-METHODE-FLOOR_42441.aspx

Hein christian Wink

jeudi 25 octobre 2007 11:33 by john

# re: SQL Server : Conserver la date ou l’heure d’un datetime (Comparaison des méthodes)

Bonjour,

J'ai trouvé cet article très intéressant, et je m'en suis servi pour optimisé des requêtes qui tronquaient l'heure en convertissant en chaines...

J'aimerais ajouter ma pierre à l'édifice.

Voici une autre méthode pour garder que la date, légèrement moins rapide :

SELECT cast(datediff(day,0,X) as datetime) FROM DateTable -- 3235 ms

en comparaison la méthode la plus rapide donne :

SELECT cast(cast(cast(X as float) as int) as datetime) FROM DateTable -- 3125 ms

Après par contre j'ai trouvé 2 autres méthodes plus rapide pour garder que l'heure :

SELECT X-datediff(day, 0, X) FROM DateTable -- 3448 ms

SELECT X-cast(cast(X as float) as int) FROM DateTable -- 3339 ms

l'autre méthode donnait :

SELECT cast(cast(X as binary(4)) as datetime) FROM DateTable -- 3732 ms

Le gros avantage, est qu'il n'est plus nécessaire de faire attention au type de donnée source.

Cela marche aussi bien pour les datetime que pour les smalldatetime.

PS : pour mes calculs de durées, j'ai travaillé sur une base sous SQL server 2000, sur une table avec 3 millions d'enregistrements.

Et j'ai demandé un min, pour que tout soit calculé, mais qu'il n'y ai pas de temps perdu à me renvoyer des millions de lignes.

Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- T_PAAMAYIM_NEKUDOTAYIM par MadMatt le il y a 8 heures et 58 minutes

- Et je mets le son.... par Pierrick's Blog le il y a 13 heures et 4 minutes

- SharePoint : Comment interdire l’accès à un utilisateur pour tous les sites d’une Web Application par Blog Technique de Romelard Fabrice le 07-18-2008, 19:05

- VPC - Reset de la position de la console par Blog technique de Nicolas Boonaert le 07-18-2008, 16:29

- Un bug dans IE rendra cette page… non-imprimable ! par Le blog de FremyCompany le 07-18-2008, 15:33

- Quelques retours sur Google Protocol Buffers par Julien Chable le 07-18-2008, 11:10

- SharePoint et le multilinguisme : Comment gérer la traduction des propriétés dans les toolbars des WebParts par The Mit's Blog le 07-18-2008, 10:53

- [Open XML] Les liens de la semaine 14/07/2008 par Julien Chable le 07-18-2008, 10:29

- Une nouvelle version des TFS Power tools est disponible par Michel Perfetti [Miiitch] le 07-18-2008, 09:37

- EF et le testeur fou par Matthieu MEZIL le 07-18-2008, 07:34