Oracle
 sql >> Base de données >  >> RDS >> Oracle

Pourquoi la vérification de null ralentit-elle cette requête ?

La seule façon que je peux penser pour obtenir ce genre de différence de vitesse d'exécution serait (a) d'avoir un index sur field4 , et (b) avoir beaucoup de blocs de données vides ; peut-être à partir d'une ligne des hautes eaux fixée très haut par des charges répétées en chemin direct.

La première requête utiliserait toujours l'index et fonctionnerait comme prévu. Mais comme les valeurs nulles ne sont pas indexées, l'index ne peut pas être utilisé pour vérifier que le or field4 is null condition, il reviendrait donc à une analyse complète de la table.

Cela en soi ne devrait pas être un problème ici, car une analyse complète de la table de 7000 lignes ne devrait pas prendre longtemps. Mais puisque c'est l'est prend tellement de temps, quelque chose d'autre se passe. Une analyse complète de la table doit examiner chaque bloc de données alloué à la table pour voir s'ils contiennent des lignes, et le temps qu'il prend suggère qu'il y a beaucoup plus de blocs que nécessaire pour contenir 7000 lignes, même avec un stockage CLOB en ligne.

Le moyen le plus simple d'obtenir un grand nombre de blocs de données vides est d'avoir beaucoup de données, puis d'en supprimer la plupart. Mais je crois que vous avez dit dans un commentaire maintenant supprimé sur une question précédente que les performances étaient correctes et se sont détériorées. Cela peut arriver si vous faites des insertions de chemin direct , en particulier si vous « actualisez » les données en les supprimant, puis en insérant de nouvelles données en mode de chemin direct. Vous pourriez faire cela avec des insertions qui ont le /*+ append */ indice; ou en parallèle ; ou via SQL*Loader. Chaque fois que vous le faisiez, la ligne des hautes eaux se déplaçait, car les anciens blocs vides ne seraient pas réutilisés ; et à chaque fois les performances de la requête qui vérifie les valeurs nulles se dégraderaient un peu. Après de nombreuses itérations, cela commencerait vraiment à s'additionner.

Vous pouvez consulter le dictionnaire de données pour voir combien d'espace est alloué à votre table (user_segments etc.), et comparez cela à la taille des données que vous pensez avoir réellement. Vous pouvez réinitialiser le HWM en reconstruisant la table, par exemple en faisant :

alter table mytable move;

(de préférence dans une fenêtre de maintenance !)

En tant que démo, j'ai exécuté un cycle pour insérer et supprimer 7000 lignes par chemin direct plus d'une centaine de fois, puis j'ai exécuté vos deux requêtes. Le premier a pris 0,06 seconde (dont une grande partie est une surcharge SQL Devleoper); le second a pris 1.260. (J'ai également couru Gordon's, qui a obtenu un temps similaire, car il doit encore faire un FTS). Avec plus d'itérations, la différence deviendrait encore plus marquée, mais je manquais d'espace... J'ai ensuite fait un alter table move et réexécutez votre deuxième requête, qui a ensuite pris 0,05 seconde.