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

- [Refactoring] ReSharper pour Visual Studio 2010 (Preview) par Thomas Jaskula le il y a 27 minutes

- [Refactoring] Analyser vos exceptions avec ReSharper Exceptional par Thomas Jaskula le il y a 1 heure et 41 minutes

- SharePoint 2007 : patterns & practices SharePoint Guidance par Philippe Sentenac [MVP SharePoint] le il y a 15 heures et 21 minutes

- [Visual Studio 2010] Les tests cases c’est bien, mais je vais devoir tout réécrire ? par Etienne Margraff le il y a 16 heures et 17 minutes

- MVP[Gribouillon].AddYear par The Grib's Lair [Sébastien PICAMELOT - MVP SharePoint] le il y a 16 heures et 32 minutes

- Clinique INSIA - Projet de fin d’Etudes (Silverlight 3 MVVM et OutOfBrowser, WCF, TFS) - Part 1 par David REI le 07-02-2009, 23:38

- C’est la crise ? Bah pourquoi cramer du budget pub alors ? par Nix's Blog le 07-02-2009, 15:31

- Soyons MVP ! par TheSaib .NET blog le 07-02-2009, 12:15

- SharePoint : Gestion des Erreurs 6398, 7076 et 6482 par Blog Technique de Romelard Fabrice le 07-02-2009, 11:53

- EF avec WPF par Matthieu MEZIL le 07-02-2009, 10:18