2010-04-10 5 views
4

J'ai une table qui contient environ 49403459 enregistrements.Comment optimiser une requête Oracle qui a to_char dans la clause where pour la date

Je souhaite interroger le tableau sur une plage de dates. dites 04/10/2010 à 04/10/2010. Cependant, les dates sont stockées dans la table sous le format 10-APR-10 10.15.06.000000 AM (horodatage).

En conséquence, quand je fais

SELECT bunch,of,stuff,create_date 
FROM myTable 
WHERE TO_CHAR (create_date,'MM/DD/YYYY)' >= '04/10/2010' 
AND TO_CHAR (create_date, 'MM/DD/YYYY' <= '04/10/2010' 

je reçois 529 lignes mais en 255.59 secondes! Ce qui est parce que je suppose que je fais TO_CHAR sur chaque enregistrement.

Cependant, quand je fais

SELECT bunch,of,stuff,create_date 
FROM myTable 
WHERE create_date >= to_date('04/10/2010','MM/DD/YYYY') 
AND create_date <= to_date('04/10/2010','MM/DD/YYYY') 

puis-je obtenir 0 résultats en 0.14 secondes.

Comment puis-je effectuer cette requête rapidement et obtenir des résultats valides (529)?

À ce stade, je ne peux pas modifier les index. En ce moment je pense que l'index est créé sur la colonne create_date.

Comment puis-je convertir les deux plages de dates afin que la première plage de dates soit convertie en horodatage avec tous les 0 et que la seconde soit convertie en horodatage correspondant au dernier horodatage de la date. Si ça a du sens...?

Ce qui suit where va chercher aucun résultat soit:

WHERE    
create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF') 
AND 
create_date <= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF') 

Répondre

2

Dans votre première requête, vous êtes en train de faire une comparaison de caractères plutôt qu'une comparaison de la date, qui ne devrait pas produire des résultats corrects.

Par exemple, en utilisant votre logique, 01/02/2009 sera supérieure à 01/01/2010 car le composant jour « 02 » est supérieure à la composante de jour « 01 » lorsque l'on compare les personnages et l'année ne seront jamais évaluées.

+0

merci. J'ai essayé cela mais je n'obtiens pas de résultats. S'il vous plaît voir mon edit – Josh

+0

J'ai édité ma réponse. Je pense que votre deuxième requête est probablement correcte. La première requête vous donne des résultats incorrects. – newdayrising

+0

non ... Je peux interroger la table et voir qu'il y a des enregistrements créés aujourd'hui. .. – Josh

2

Cela fonctionne:

WHERE    
create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF') 
AND 
create_date <= to_timestamp('04/10/2010 23:59:59:123000','MM/DD/YYYY HH24:MI:SS.FF') 
1
SELECT bunch,of,stuff,create_date 
    FROM myTable 
WHERE create_date >= to_date('04/10/2010','MM/DD/YYYY') 
    AND create_date < to_date('04/11/2010','MM/DD/YYYY') 

La date 04/10/2010 inclut toutes les valeurs de date à partir de minuit le 10 jusqu'à 11:59:59 PM, afin d'obtenir tout le moins 11 sera couvrir toutes les bases. Une alternative consiste à s'assurer que les données de myTable ont le champ CREATE_DATE tronqué lors de la saisie de données; Je préfère faire cela pour les champs DATE, et si je me soucie des composants de temps, j'utilise TIMESTAMPs.

3

Bien sûr, cela ne fonctionne pas:

WHERE    
    create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF') 
AND 
    create_date <= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF') 

Parce que cela ne renvoient les lignes où le create_date est 4/10/2010 0h00 exactement!

Si vous souhaitez obtenir toutes les lignes où create_date se produit chaque fois le jour de 4/10/2010, utilisez ceci:

WHERE    
    create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF') 
AND 
    create_date < to_timestamp('04/11/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF') 

ou si vous préférez:

WHERE create_date BETWEEN to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF') 
         AND to_timestamp('04/10/2010 23:59:59.999999','MM/DD/YYYY HH24:MI:SS.FF') 

Par Quand vous voulez représenter minuit, vous pouvez laisser toutes les autres parties. Donc, vous pourriez dire:

WHERE    
    create_date >= to_timestamp('04/10/2010','MM/DD/YYYY') 
AND 
    create_date < to_timestamp('04/11/2010','MM/DD/YYYY') 
4

je reçois 529 lignes, mais en 255.59 secondes! Ce qui est parce que je suppose que je fais TO_CHAR sur chaque enregistrement.

Si vous deviez generate an execution plan pour votre première requête ...

explain plan for 
SELECT bunch,of,stuff,create_date 
FROM myTable 
WHERE TO_CHAR (create_date,'MM/DD/YYYY)' >= '04/10/2010' 
AND TO_CHAR (create_date, 'MM/DD/YYYY') <= '04/10/2010' 
/

... vous verriez qu'il effectue une analyse complète de la table. C'est parce que le to_char() empêche l'utilisation de votre index sur CREATE DATE.

Vous ne dites pas combien de temps il a fallu pour retourner les résultats lors de l'exécution ...

SELECT bunch,of,stuff,create_date 
FROM myTable 
WHERE    
create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF') 
AND 
create_date <= to_timestamp('04/10/2010 23:59:59:123000','MM/DD/YYYY HH24:MI:SS.FF') 
/

... mais je pense qu'il était beaucoup plus proche de 0,14 secondes à 4 minutes.

0

Votre première requête effectue une comparaison de chaîne avec de mauvais résultats. Votre 2ème requête doit être:

OÙ create_date> = TRUNC (to_date ('04/10/2010' , 'MM/JJ/AAAA))

ou ajouter hh : mi: ss au prédicat. Cela ne fonctionne pas simplement parce que vous formatez la date différemment de ce qu'Oracle attend.

Questions connexes