Performance sur les dates ?

Performance sur les dates ? - SQL/NoSQL - Programmation

Marsh Posté le 04-04-2007 à 17:32:36    

Salut tlm !
 
Voilà, lorsque je fais une requête permettant d'afficher qqs infos contenues dans une table, quelle est la requête la plus performante entre ces deux là (sauf erreur, le résultat retourné étant identique) :
 
Exemple en Oracle :
 
SELECT *
FROM maTable
WHERE champDate >= TO_DATE('20070404','YYYYMMDD')
AND champDate < TO_DATE('20070405','YYYYMMDD')
 
ou
 
SELECT *
FROM maTable
WHERE champDate = TO_DATE('20070404','YYYYMMDD')
 
Question bonus : en supposant qu'une de ces deux requêtes est plus performante que l'autre, fonctionnerait-elle à l'identique sur tous les SGBD (MySQL, SQL Serveur, etc...) ?
 
 
Merci d'avance pour vos réponses !
Lionel.

Reply

Marsh Posté le 04-04-2007 à 17:32:36   

Reply

Marsh Posté le 04-04-2007 à 18:31:34    

A mon avis, ca va etre la deuxième.
Moins de tests à faire sachant que pour déterminer si c'est supérieur ou inférieur, il doit scanner toute la chaine (enfin du début à une certaine position tant que ca matche)
 
Mais je peux me tromper :o
 
Fait des benchs :)

Reply

Marsh Posté le 04-04-2007 à 21:08:26    

c'est pas les mêmes requêtes :o

Reply

Marsh Posté le 04-04-2007 à 22:16:28    

couak a écrit :

c'est pas les mêmes requêtes :o


 
Tu penses que je n'aurais pas le même résultat avec ces deux requêtes ?

Reply

Marsh Posté le 05-04-2007 à 00:18:59    

allez je suis d'une âme généreuse ce soir :D rien ne vaut la pratique et les tests

Code :
  1. SQL> create table pouet (champdate date);
  2. Table created.
  3. SQL> insert into pouet values (sysdate);
  4. 1 row created.
  5. SQL> select * from pouet;
  6. CHAMPDATE
  7. ---------
  8. 05-APR-07
  9. SQL> select * from pouet where champdate>=to_date('20070405','YYYYMMDD') and champdate<to_date('20070406','YYYYMMDD');
  10. CHAMPDATE
  11. ---------
  12. 05-APR-07
  13. SQL> select * from pouet where champdate=to_date('20070405','YYYYMMDD');
  14. no rows selected


 
Une idée du problème ? Moi j'en ai une :

Code :
  1. SQL> select to_char(champdate, 'DD/MM/YYYY HH24:MI:SS') from pouet;
  2. TO_CHAR(CHAMPDATE,'
  3. -------------------
  4. 05/04/2007 00:12:14
  5. SQL> select to_char(to_date('20070405','YYYYMMDD'), 'DD/MM/YYYY HH24:MI:SS') from dual;
  6. TO_CHAR(TO_DATE('20
  7. -------------------
  8. 05/04/2007 00:00:00


 
Toujours pas d'idée ?

Code :
  1. SQL> select champdate-to_date('20070405','YYYYMMDD') from pouet;
  2. CHAMPDATE-TO_DATE('20070405','YYYYMMDD')
  3. ----------------------------------------
  4.                                .00849537


Tu as une différence de 0,00849537 jour entre la donnée dans la table pouet, et le 05/04/2007 à minuit, et donc tes requêtes ne sont pas les mêmes car tu es tombé dans le piège des dates sous Oracle :o
Sinon tu peux t'amuser à utiliser un BETWEEN plutôt que d'encapsuler dans des <= et > c'est plus lisible


Message édité par couak le 05-04-2007 à 00:19:48
Reply

Marsh Posté le 05-04-2007 à 10:03:54    

Ok, donc si je comprends bien, en faisant :
 
SELECT *
FROM maTable
WHERE champDate = TO_DATE('20070404','YYYYMMDD')
 
Il va ma ramener uniquement les lignes où champDate est égale exactement à '20070404000000'.
 
Je pensais qu'il allait me renvoyer toutes les lignes commençant par '20070404'  :(  
 
Bon, ben en tous cas merci d'avoir pris un peu de ton temps pour m'expliquer tout ça !
C'est super sympa !


Message édité par pot2yaourt le 05-04-2007 à 10:04:22
Reply

Marsh Posté le 05-04-2007 à 11:03:01    

like au lieu de égale dans ce cas mais BETWEEN est préférable :)

Reply

Marsh Posté le 05-04-2007 à 21:30:46    

orafrance a écrit :

like au lieu de égale dans ce cas mais BETWEEN est préférable :)


 
Donc, pour résumer, la bonne méthode pour faire des tris sur les dates :
 
SELECT *
FROM maTable
WHERE champDate BETWEEN TO_DATE('20070405','YYYYMMDD')
AND TO_DATE('20070406','YYYYMMDD')
 
J'ai juste ?!

Reply

Marsh Posté le 05-04-2007 à 23:32:15    

bon encore une fois : as-tu essayé ?

Reply

Marsh Posté le 06-04-2007 à 00:07:36    

je vois pas la différence entre > and < et between. Un SGBD à la con peut être

Reply

Marsh Posté le 06-04-2007 à 00:07:36   

Reply

Marsh Posté le 06-04-2007 à 08:53:46    

couak a écrit :

bon encore une fois : as-tu essayé ?


 
Ben oui, je viens d'essayer et ça fonctionne : ça me ramène bien le même nombre de lignes.
 
Par contre, je n'ai pas vu de différence de temps entre >= < et BETWEEN... sous Oracle hein ! P't'être qu'il y a une différence notable sur du MySQL ou SQL Serveur... ?

Message cité 1 fois
Message édité par pot2yaourt le 06-04-2007 à 08:55:08
Reply

Marsh Posté le 06-04-2007 à 08:55:38    

ouaip, between c'est >= <= :)

Reply

Marsh Posté le 06-04-2007 à 09:55:28    

chuis d'accord avec pikti. le souci du between, c'est que ça va donner un résultat faux :/.

Reply

Marsh Posté le 10-04-2007 à 09:51:27    

Taz a écrit :

je vois pas la différence entre > and < et between. Un SGBD à la con peut être


 
il n'y a pas de différence ;)
 

MagicBuzz a écrit :

chuis d'accord avec pikti. le souci du between, c'est que ça va donner un résultat faux :/.


 
bah non, pourquoi ?  :heink:

Reply

Marsh Posté le 10-04-2007 à 13:00:39    

ben si. between ça fait >= et <=
 
donc avec l'exemple, le between entre le 01/01/2000 et le 02/01/2000 pour récupérer les élément au 01/01/2000, ça fait faire du 01/01/2000 00:00:00 au 02/01/2000 00:00:00 inclus.
=> donc si j'un un élément enregistré au 02/01/2000 00:00:00, il ne doit pas être retourné, mais le serva par le between.
Et le problème d'un champ datetime, c'est qu'on va vite fait d'enregister des dates uniquement, sans l'heure (et donc se heurter systématiquement à ce problème, puisqu'une date dans un datetime, c'est la date à minuit pile)

Reply

Marsh Posté le 11-04-2007 à 08:35:11    

évidemment il faut adapter les bornes  :D

Reply

Marsh Posté le 11-04-2007 à 10:22:36    

pot2yaourt a écrit :

Par contre, je n'ai pas vu de différence de temps entre >= < et BETWEEN


 

pikti a écrit :

between c'est >= <= :)


 
 
C'était juste pour rectifier une affirmation erronée  :jap:

Reply

Marsh Posté le 11-04-2007 à 10:32:08    

genre, le truc que j'ai expliqué 2 lignes plus haut :ange:

Reply

Marsh Posté le 12-04-2007 à 09:30:39    

ouais c'est trop injuste :/
 
:D

Reply

Marsh Posté le 13-04-2007 à 00:10:13    

Une autre possibilité :
 
SELECT *
FROM maTable
WHERE TRUNC(champDate) = TO_DATE('20070404','YYYYMMDD');
 
Le TRUNC va renvoyer la partie date uniquement, ce qui revient à mettre l'heure à minuit.

Reply

Marsh Posté le 13-04-2007 à 09:28:43    

et il va éviter d'utiliser l'éventuel index... dans un sujet sur les performances c'est moyen :D

Reply

Marsh Posté le 13-04-2007 à 10:22:01    

orafrance a écrit :

et il va éviter d'utiliser l'éventuel index... dans un sujet sur les performances c'est moyen :D


Code :
  1. create index index_degueux on matable (trunc(champdate));

[:zerod]

Reply

Marsh Posté le 13-04-2007 à 10:37:26    

le nom est bien choisi en effet :D

Reply

Marsh Posté le 13-04-2007 à 14:02:33    

faut voir pour l'index degueu... ca peut parfois se justifier
 
sinon un between trunc(ma_date) and (trunc(ma_date)+0.99999999999999999999) ca devrait le faire, faut voir le détail de définition de tes valeurs
 
mais >= trunc(ma_date) and <trunc(ma_date)+1 jcrois pas que oracle le gérerai mal

Reply

Marsh Posté le 13-04-2007 à 14:12:10    

S'il y a un index sur champDate :
 
SELECT *
FROM maTable
WHERE champDate BETWEEN TO_DATE('20070404','YYYYMMDD') AND TO_DATE('20070404 235959','YYYYMMDD HH24MISS')
 
ou encore
 
 
SELECT *
FROM maTable
WHERE champDate BETWEEN TO_DATE('20070404','YYYYMMDD') AND TO_DATE('20070404','YYYYMMDD') + 1 - 1/(24*3600)

Reply

Marsh Posté le 13-04-2007 à 14:23:46    

vous vous faites des noeuds au cerveau pour pas grand chose :/ vous êtes en train d'essayer de gratter 1/4 de cycle de processeur

Reply

Marsh Posté le 13-04-2007 à 15:40:41    

casimimir a écrit :

faut voir pour l'index degueu... ca peut parfois se justifier
 
sinon un between trunc(ma_date) and (trunc(ma_date)+0.99999999999999999999) ca devrait le faire, faut voir le détail de définition de tes valeurs
 
mais >= trunc(ma_date) and <trunc(ma_date)+1 jcrois pas que oracle le gérerai mal


 
une date c'est précis à la seconde prêt alors si tu elèves 1/3600*24 çà suffit :)

Reply

Marsh Posté le 13-04-2007 à 18:23:29    

avec sql server c'est quand même plus simple... tu fais un round(ladate,0) et tu bosses qu'avec la partie date.
et vu que la date est un float, le round n'impacte pas l'utilisation des index :D

Reply

Marsh Posté le 16-04-2007 à 09:55:34    

TRUNC fait pareil :D

Reply

Marsh Posté le 16-04-2007 à 11:45:30    

ben alors pkoi tu dis qu'il utilise pas les index ?
normalement il devrait, puisque le trunc ne peut pas changer l'ordre des données :??:

Reply

Marsh Posté le 16-04-2007 à 14:15:28    

ha oui, en effet, le résultat est le même mais pas le temps de le voir :D
 
sous Oracle, quelque soit la fonction appliquée à une colonne inhibe l'usage de l'index... éventuellement, il faut créer un index de fonction ;)

Reply

Marsh Posté le 16-04-2007 à 14:22:17    

Quelle merde Oracle :D
 
Sous SQL Server, ça dépend de la fonction.
Si SQL Server détecte que l'ordre de tri n'est pas impacté par la fonction, alors il effectue la requête sur l'index en fonction des données passées en paramètre, puis applique la fonction sur le résultat du filtre.
 
Donc à priori, le Round ne pose pas de problème.
 
Là où il peut poser problème, c'est sur un sous-tri après le round :  
 
col1 col2
1,2 A
1,1 B
 
=> order by col1, col2 retourne les lignes dans l'ordre "B", "A"
=> order by round(col1, 0), col2 retourne les lignes dans l'ordre "A", "B"
 
Il faudra vérifier le plan d'exécution sur pour ce type de requête. A mon avis l'index est utilisé une première fois, puis un filtre sans index est effectué sur le résultat final. Performances dégradées donc, mais dans le cas d'un between ça ne devrait pas poser de problème.


Message édité par MagicBuzz le 16-04-2007 à 14:23:01
Reply

Marsh Posté le 16-04-2007 à 14:30:40    

Après tests, c'est tout comme j'ai dit :D
 
Structure de la table de test :
create table TSTROUND (num as numeric(18,9), val as varchar(50))
create index TSTROUND_IX on TSTROUND (num, val)
 
 
select *
from tstround
order by round(num, 0), val
 
PE :
SELECT 0%
SORT 78%
Compute Scalar 0%
Index Scan 22%
 
=> C'est donc bien ça : l'index est appelé pour dégrossir le travail, puis les données sont re-triées à la main
 
select *
from tstround
order by num, val
 
PE :
SELECT : 0%
Index Scan : 100%
(sans surprise)
 
select *
from tstround
where num between 1 and 3
 
PE : (partage en live total :pt1cable:) - c pourtant le cas le plus simple :D
http://magicbuzz.multimania.com/files/partageenlive.png
 
select *
from tstround
where round(num, 0) between 1 and 3
 
PE :
SELECT : 0%
Index Scan : 100%
(faut pas chercher à comprendre :D)
 
select *
from tstround
where round(num, 0) between 1 and 3
order by round(num, 0), val
 
PE :
SELECT 0%
SORT 78%
Compute Scalar 0%
Index Scan 22%
(le même que le premier)


Message édité par MagicBuzz le 16-04-2007 à 14:45:20
Reply

Marsh Posté le 16-04-2007 à 14:44:26    

Edit : En fait, c'est pas trop un partage en live la capture d'écran...
 
Vu qu'on ne passe pas par round(), il est capable à partir des constantes passées au between d'isoler exactement la partie de l'index correspondant à l'ensemble de valeurs (c'est donc effectivement bien plus performant que le Index Scan qui nécessite de se pallucher tout l'index. Cependant, on voit bien que SQL Server est tout de même capable d'analyser l'index lorsqu'on passer par une fonction)


Message édité par MagicBuzz le 16-04-2007 à 14:47:46
Reply

Marsh Posté le 16-04-2007 à 16:28:50    

les plans d'exécution sous SQL-Server stro laid :D
 
Sinon, en effet, parfois Oracle est moins bon... faut bien laisser la place à l'amélioration sinon comment vendre les versions suivantes  :whistle:


Message édité par orafrance le 16-04-2007 à 16:29:29
Reply

Marsh Posté le 16-04-2007 à 17:15:55    

moi je les aime bien les PE de SQL Server. c'est mieux que les listings que t'as sous SQL+ :p
 
je trouve à bien lisible moi (pis quand tu passes la papatte dessus, t'as plein d'infos en plus)


Message édité par MagicBuzz le 16-04-2007 à 17:16:06
Reply

Marsh Posté le 17-04-2007 à 11:22:57    

tu as la même chose sous Oracle, il suffit d'utiliser la console d'admin livrée avec Oracle client ou SQL Developper encore gratuit pour l'instant :)


Message édité par orafrance le 17-04-2007 à 11:23:10
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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