[ORACLE] comparaison de date

comparaison de date [ORACLE] - SQL/NoSQL - Programmation

Marsh Posté le 27-06-2003 à 09:44:07    

il est plus rapide de faire des comparaisons (< et > ) au format date ou au format chaine de caracteres?
pour faire les comparaisons entre type date, on utilise juste les opérateurs ou il faut utiliser des fonctions?
(non je ne pe pas utilise Between...)

Reply

Marsh Posté le 27-06-2003 à 09:44:07   

Reply

Marsh Posté le 27-06-2003 à 10:09:43    

Une date (du moins dans SQL Server, mais pour Oracle, ça doit être à peut près la même chose) est stockée dans un float.
 
La partie entière contient le nombre de jours écoulés depuis le 01/01/1900 (ou un truc du genre), et la partie décimale contient le nombre de milli-secondes écoulées depuis le début de la journée indiquée dans la partie entière. Sous Unix (Oracle repose peut-être plutôt là dessus) c'est stocké dans un double, et c'est le nombre de milli-secondes depuis le 01/01/1900 (ou je ne sais plus quelle date, je sais jamais :D)
 
Donc, pour faire une comparaison entre un deux dates, il s'agit d'une comparaison de float ou de double, ce qui est en effet bien plus rapide qu'une comparaison de chaîne.
 
Deplus, pour faire une comparaison de date à partir d'une chaîne, il faut faire attention au format de la date... En effet, "01/12/2003" < "05/01/2003", alors qu'au niveau date (au format international) c'est faut. Le format anglais quand à lui commence à merde quand l'année change.
 
Il faut donc se baser sur le format ISO, qui est de la forme "YYYYMMDD HH:MM:SS MS"
A ce moment, la comaraison sera bonne.
 
Pour en revenir au niveau des performances, truc simple :
-> Niveau performances pures théoriques, la comparaison entre deux dates de type date est énormément plus rapide.
 
MAIS, tu remarqueras que dès que tu as une date dans une requête, to fait très souvent des TO_CHAR() et des TO_DATE() à n'en plus finir. Ceci est "très" consommateur, surtout si c'est sur un des champs scannés que tu fais ce traîtement (il faut mieu adapter les champs minoritaires en nombre au format des champs majoritaires en nombre que l'inverse, donc ne jamais faire :
 
where TO_CHAR(champDate, 'YYYYMMDD') > '20030101'
 
mais plutôt :
 
where champDate > TO_DATE('20030101', 'YYYYMMDD')
 
Mais c'est pas toujours évident de s'en sortir comme ça, et pour des raisons de compatibilité (connection ODBC, interrogation de la base avec un client dans une langue différente) il vaut généralement mieu stocker la date ISO au format char(8).
 
En effet, outre le faire qu'on a plus besoin de faire 50 conversions dans tous les sens, il y a un autre gain notable : si on index les champs date, alors niveau SGBD, ils sont vus comme un arbre, basé sur des entiers. Le gain est donc énorme. Par contre, di tu stockes au format natif date, le passage à un arbre de nombres sera moindre, puisque c'est déjà des nombres (tu ne gagnes que le gain dû à l'arborescence - ce qui est déjà pas mal). Anyway : Au final, si tu index le champ, les perfs seront "rigoureusement" les mêmes entre un champ de type char ou un champ de type date. Il y a une différence minime, mais qui  est suffisament réduite pour être ignorée.

Reply

Marsh Posté le 27-06-2003 à 10:13:13    

MagicBuzz a écrit :

Une date (du moins dans SQL Server, mais pour Oracle, ça doit être à peut près la même chose) est stockée dans un float.
 
La partie entière contient le nombre de jours écoulés depuis le 01/01/1900 (ou un truc du genre), et la partie décimale contient le nombre de milli-secondes écoulées depuis le début de la journée indiquée dans la partie entière. Sous Unix (Oracle repose peut-être plutôt là dessus) c'est stocké dans un double, et c'est le nombre de milli-secondes depuis le 01/01/1900 (ou je ne sais plus quelle date, je sais jamais :D)
 
Donc, pour faire une comparaison entre un deux dates, il s'agit d'une comparaison de float ou de double, ce qui est en effet bien plus rapide qu'une comparaison de chaîne.
 
Deplus, pour faire une comparaison de date à partir d'une chaîne, il faut faire attention au format de la date... En effet, "01/12/2003" < "05/01/2003", alors qu'au niveau date (au format international) c'est faut. Le format anglais quand à lui commence à merde quand l'année change.
 
Il faut donc se baser sur le format ISO, qui est de la forme "YYYYMMDD HH:MM:SS MS"
A ce moment, la comaraison sera bonne.
 
Pour en revenir au niveau des performances, truc simple :
-> Niveau performances pures théoriques, la comparaison entre deux dates de type date est énormément plus rapide.
 
MAIS, tu remarqueras que dès que tu as une date dans une requête, to fait très souvent des TO_CHAR() et des TO_DATE() à n'en plus finir. Ceci est "très" consommateur, surtout si c'est sur un des champs scannés que tu fais ce traîtement (il faut mieu adapter les champs minoritaires en nombre au format des champs majoritaires en nombre que l'inverse, donc ne jamais faire :
 
where TO_CHAR(champDate, 'YYYYMMDD') > '20030101'
 
mais plutôt :
 
where champDate > TO_DATE('20030101', 'YYYYMMDD')
 
Mais c'est pas toujours évident de s'en sortir comme ça, et pour des raisons de compatibilité (connection ODBC, interrogation de la base avec un client dans une langue différente) il vaut généralement mieu stocker la date ISO au format char(8).
 
En effet, outre le faire qu'on a plus besoin de faire 50 conversions dans tous les sens, il y a un autre gain notable : si on index les champs date, alors niveau SGBD, ils sont vus comme un arbre, basé sur des entiers. Le gain est donc énorme. Par contre, di tu stockes au format natif date, le passage à un arbre de nombres sera moindre, puisque c'est déjà des nombres (tu ne gagnes que le gain dû à l'arborescence - ce qui est déjà pas mal). Anyway : Au final, si tu index le champ, les perfs seront "rigoureusement" les mêmes entre un champ de type char ou un champ de type date. Il y a une différence minime, mais qui  est suffisament réduite pour être ignorée.


ok merci

Reply

Marsh Posté le 27-06-2003 à 10:35:27    

les comparaisons de date marche tres bien mais je ne comprend pas pkoi ceci ne marche pas
to_date(REPLACE(:DP,'','01011000'),'DDMMYYYY')
 
j'utilise un replace car la case date de début de la période est facultative
si on ne donne pas de date, je prend une date quelconque < a toutes celles de la base
mais le replace doit poser un pb car la conversion ne marche plus et oracle m'indique que le mois donné n'est pas valide alors qu il l'est
 
pendant que j y suis, le replace ne comprend pas que '' veut dire rien n'est donné dans le formulaire et on est obligé de donner un espace dans le formulaire alors qu'il n'y en a pas au milieu de ''... comment ca se fait???

Reply

Marsh Posté le 27-06-2003 à 11:01:18    

au lien de faire un replace, fait un nvl(:DP, '01011800')
 
et évite d'utiliser 1000 comme année, utilise un truc plus proche. 1800 fonctione (sûr et certain) je m'en sert moi-même dans ce genre de situations. mais l'an 1000 n'a aucun intérêt pour quoi que ce soit (à par quelques historiens qui reprensentent une part négligeable du marché ;)) et du coup je suis pas sûr qu'orale sâche le représenter.

Reply

Marsh Posté le 27-06-2003 à 11:03:03    

PS, sinon, Oracle c'est de la grosse merde en barre, donc :
 
'' = NULL chez eux.
 
N'utilise jamais ''.

Reply

Marsh Posté le 27-06-2003 à 11:09:21    

MagicBuzz a écrit :

PS, sinon, Oracle c'est de la grosse merde en barre, donc :
 
'' = NULL chez eux.
 
N'utilise jamais ''.


 
ok pour la date
je mettais ca comme ca mais effectivemenje pe remonter bcp plus
(du genre 1990)
et effectivement quand on ne met rien ca correspond bien a null
c bizzare paske qd je me servais de '', ca correspondait a un espace dans le formulaire...
mais alors deux espaces dans le formulaire correspondent a un espace dans le code et ... :heink:  euh...
merci bien en tout cas paske ca marche

Reply

Marsh Posté le 27-06-2003 à 11:13:56    

C'est ce que je dis : Oracle, c'est de la merde en barre.
 
' ' = chaîne vide.
 
Donc si tu as que des espaces dans une chaîne, il va en manquer un, qui est remplacé par la chaîne vide.
 
Et la chaîne vide = null, ce qui est super pratique pour savoir si un champ est non renseigné, ou a été effacé...

Reply

Marsh Posté le 01-07-2003 à 14:35:48    

comment je fais pour comparer 2 dates qui sont toutes les deux au format char mais les 2 dans deux formats différents :
francais 01072003 et l autre en iso 20030701
 
je suis obligé de faire des to_date ou un to_char(to_date()) ou alors il existe une autre solution?
 
merci

Reply

Marsh Posté le 01-07-2003 à 15:48:22    

Le format DD/MM/YYYY n'est pas le format "français", mais le format internationnal. Y'a que les anglais qui inversent jour et mois, les américains par exemple utilisent le même système que nous.
 
Bah je te conseille :
 
to_char(to_date(la_date_is, 'DDMMYYYY'), 'YYYYMMDD') = la_date_iso

Reply

Marsh Posté le 01-07-2003 à 15:48:22   

Reply

Marsh Posté le 01-07-2003 à 15:59:15    

MagicBuzz a écrit :

Le format DD/MM/YYYY n'est pas le format "français", mais le format internationnal. Y'a que les anglais qui inversent jour et mois, les américains par exemple utilisent le même système que nous.
 
Bah je te conseille :
 
to_char(to_date(la_date_is, 'DDMMYYYY'), 'YYYYMMDD') = la_date_iso


 
ok merci  :jap:

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed