IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

SQL Oracle Discussion :

Le + rapide : une clause WHERE dans chaque sous-requête ou une seule clause WHERE dans la requête principale ?


Sujet :

SQL Oracle

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    66
    Détails du profil
    Informations personnelles :
    Âge : 57
    Localisation : France, Deux Sèvres (Poitou Charente)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 66
    Par défaut Le + rapide : une clause WHERE dans chaque sous-requête ou une seule clause WHERE dans la requête principale ?
    Bonjour à tous,

    Je souhaiterais optimiser le temps d'exécution d'une requête contenant plusieurs sous-requêtes en UNION ALL et j'aurais besoin de savoir où il est préférable de placer ma ou mes clauses WHERE pour restreindre la profondeur de l'historique retourné.

    Je suis certain que ma question est très basique, et je pourrais évidemment faire le test en réel, mais comme le temps d'exécution actuel de ma requête est de plus de 3 heures, mes tests risquent d'être très longs... Donc j'apprécierais vraiment votre aide svp.

    Donc, est-il plus rapide de faire ceci (une seule clause WHERE dans la requête principale) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    SELECT req.champ1, req.annee_creation
    FROM (
      SELECT champ1, annee_creation
      FROM table1
      UNION ALL
      SELECT champ1, annee_creation
      FROM table2
    ) req
    WHERE req.annee_creation = 2020;
    Ou bien ceci ? (une clause WHERE dans chaque sous-requête) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    SELECT req.champ1, req.annee_creation
    FROM (
      SELECT champ1, annee_creation
      FROM table1
      WHERE annee_creation = 2020
      UNION ALL
      SELECT champ1, annee_creation
      FROM table2
      WHERE annee_creation = 2020
    ) req;
    Merci d'avance pour votre aide.

    Bonne journée.

  2. #2
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Bonjour,

    Moi je conseille le 2, les restrictions au niveau le plus bas (dans chaque Select). Même si l'optimiseur Oracle peut transformer la requête pour le gérer en automatique, rien n'est jamais sûr.

  3. #3
    Membre Expert
    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Décembre 2019
    Messages
    1 176
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Décembre 2019
    Messages : 1 176
    Par défaut
    Bonjour,

    Sur le principe je préfère restreindre la sélection de données dès le plus bas niveau, donc comme McM je partirai pour l'option 2.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    66
    Détails du profil
    Informations personnelles :
    Âge : 57
    Localisation : France, Deux Sèvres (Poitou Charente)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 66
    Par défaut
    Bonjour,

    Merci beaucoup pour vos retours rapides, je vais suivre vos conseils.

    Bonne journée.

  5. #5
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    22 010
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 22 010
    Billets dans le blog
    6
    Par défaut
    Et pourquoi pas les deux ? Si l'optimiseur est assez intelligent, il se débrouillera au mieux !

    mais l'essentiel est de voir le plan de requête dans les deux cas et de comparer.

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  6. #6
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Pourquoi pas les 2 ? parce que c'est inutile et que gaspiller de la mémoire pour rajouter des conditions inutile va à l'encontre de l'Optimisation.

  7. #7
    Membre Expert
    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Décembre 2019
    Messages
    1 176
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Décembre 2019
    Messages : 1 176
    Par défaut
    Peut-être que l'optimiseur simplifiera en effet et il peut-être intéressant de jeter un oeil aux plans d'exécution, mais sur le principe je préfère appliquer les filtres directement sur les tables sources plutôt qu'au global. Il peut bien sûr avoir des exceptions, et je suppose que la requête présentée par Mafate était simplifiée pour l'exemple.

  8. #8
    Expert confirmé
    Avatar de pachot
    Homme Profil pro
    Developer Advocate YugabyteDB
    Inscrit en
    Novembre 2007
    Messages
    1 822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : Suisse

    Informations professionnelles :
    Activité : Developer Advocate YugabyteDB
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 822
    Billets dans le blog
    1
    Par défaut
    Je vois que la question est marquée 'résolue' mais j'ai du mal à comprendre toutes ces réponses qui recommandent de dupliquer le prédicat, sans raison, juste au cas où, par principe,...

    La question est:
    Citation Envoyé par Mafate Voir le message
    Donc, est-il plus rapide de faire ceci (une seule clause WHERE dans la requête principale) :
    et la réponse est: non, il n'est pas plus rapide de faire l'un ou l'autre car une transformation basique de l'optimiser, push-predicate, va de toute façon descendre au plus bas le prédicat.

    Par contre, la première requête est:
    - plus rapide à écrire
    - plus facile à comprendre
    - moins sujette à erreur

    Donc c'est clairement la bonne solution.

  9. #9
    Membre Expert
    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Décembre 2019
    Messages
    1 176
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Décembre 2019
    Messages : 1 176
    Par défaut
    Bonjour Frank,

    Les arguments que tu avances:

    Par contre, la première requête est:
    - plus rapide à écrire
    - plus facile à comprendre
    - moins sujette à erreur
    sont vraiment subjectifs. Oui c'est plus rapide à écrire, comme le sont les requêtes qui ne qualifient jamais les colonnes par pure fainéantise, mais par lesquelles on perd un temps fou à retrouver dans quelles tables ces colonnes se trouvent. En quoi mettre le critère au global plutôt qu'au niveau des 2 tables est plus facile à comprendre? Même remarque pour le fait que ce soit plus prône à l'erreur?

    Si possible ce sera bien que Mafate nous montres les plans d'exécution.
    J’essaierai de faire un test demain sur ma base pour comparer.

  10. #10
    Membre Expert
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 963
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 963
    Par défaut
    Citation Envoyé par pachot Voir le message
    - moins sujette à erreur

    Donc c'est clairement la bonne solution.
    “Moins sujette à erreur humaine...”
    le push-predicate peut toutefois avoir des effets de bord indésirés dans des situations plus complexes où par exemple la clause where externe utilise une fonction qui ne peut s’appliquer que sur les résultats finaux car un ou plusieurs des select de l’union ont d’autres where qui filtrent les résultats pour ne garder que ceux sur lesquels la fonction est garantie fonctionner (exemple un to_number sur un substr) : dans ce pattern vous pourriez avoir une mauvaise surprise car le push-predicate va aller mélanger votre where clause externe avec l’interne mais sans garantir l’ordre d’évaluation... et la fonction peut dès lors être évaluée sur des valeurs normalement exclues si l’on s’en tient à l’ordre apparent des choses à la lecture du query.

    Donc oui cela reste la bonne solution mais rester prudent si la ”where” clause externe contient une expression qui dépend des résultats des ”where” internes pour fonctionner dans tous les cas.

  11. #11
    Expert confirmé
    Avatar de pachot
    Homme Profil pro
    Developer Advocate YugabyteDB
    Inscrit en
    Novembre 2007
    Messages
    1 822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : Suisse

    Informations professionnelles :
    Activité : Developer Advocate YugabyteDB
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 822
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par JeitEmgie Voir le message
    sans garantir l’ordre d’évaluation
    Mais rien ne garantit l'ordre d'évaluation en SQL. C'est un langage déclaratif. Vraiment, il y a plusieurs manières de déclarer le résultat qu'on veut (pour raison de style, lisibilité,...) mais c'est l'optimiseur qui va choisir le plan d'exécution. Il n'y a que certains hints qui peuvent forcer l'ordre d'exécution (par exemple no_push_pred dans ce cas) mais ce n'est plus du SQL et c'est pour ça qu'ils sont en commentaires.
    Le pattern décrit (se baser sur "l’ordre apparent des choses à la lecture") est un bug de l'application. Si la fonction n'est pas valide pour toutes les valeurs possibles de la colonne ou expression, il faut le gérer (par un CASE ou un ON CONVERSION ERROR)

  12. #12
    Membre Expert
    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Décembre 2019
    Messages
    1 176
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Décembre 2019
    Messages : 1 176
    Par défaut
    Bonjour,

    Je viens de tester avec un exemple basique, les plans d'exécution sont identiques:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    create table table1(champ1, annee_creation)
    as
    select level, case when level <= 10000 then 2020 else 2020 - level end
    from dual
    connect by level <= 100000;
     
    create table table2(champ1, annee_creation)
    as
    select level, case when level <= 20000 then 2020 else 2020 - level end
    from dual
    connect by level <= 100000;
     
    create index table1_i1 on table1(annee_creation);
    create index table2_i1 on table2(annee_creation);
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    SELECT req.champ1, req.annee_creation
    FROM (
      SELECT champ1, annee_creation
      FROM table1
      UNION ALL
      SELECT champ1, annee_creation
      FROM table2
    ) req
    WHERE req.annee_creation = 2020;

    ou

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    SELECT req.champ1, req.annee_creation
    FROM (
      SELECT champ1, annee_creation
      FROM table1
      WHERE annee_creation = 2020
      UNION ALL
      SELECT champ1, annee_creation
      FROM table2
      WHERE annee_creation = 2020
    ) req
    Nom : plan_exec1.jpg
Affichages : 258
Taille : 51,0 Ko


    Le souci de préciser le critère au global c'est si on ne choisit plus la colonne mais une expression alors l'index n'est plus utilisé (c'est je pense que JeitEmgie expliquait), alors qu'il le sera toujours si le filtre est au niveau de la table:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    SELECT req.champ1, req.annee_creation
    FROM (
      SELECT champ1, annee_creation 
      FROM table1
      UNION ALL
      SELECT champ1, annee_creation - 1 
      FROM table2
    ) req
    WHERE req.annee_creation = 2020;

    Nom : plan_exec2.jpg
Affichages : 241
Taille : 43,0 Ko

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    SELECT req.champ1, req.annee_creation
    FROM (
      SELECT champ1, annee_creation
      FROM table1
      WHERE annee_creation = 2020
      UNION ALL
      SELECT champ1, annee_creation - 1
      FROM table2
      WHERE annee_creation = 2020
    ) req
    Nom : plan_exec3.jpg
Affichages : 239
Taille : 45,6 Ko

  13. #13
    Membre Expert
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 963
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 963
    Par défaut
    Citation Envoyé par pachot Voir le message
    Mais rien ne garantit l'ordre d'évaluation en SQL.
    certes, mais ici on parle spécifiquement de l’ordre d’évaluation des composants de la nouvelle WHERE clause ré-écrite par le push-predicate : avant la condition étant dans la WHERE clause externe, on pouvait légitement s’attendre à ce qu’elle soit évaluée après les conditions des select internes, or le push-predicate la déplace de telle manière que l’ordre n’est plus garantit, car il se contente de l’ajouter aux conditions du WHERE existant (et si l’on examine le texte du query ré-écrit, il l’a met en tête des clauses existantes suivi de AND... ce qui fait qu’en pratique il la met en tête de l’ordre d’évaluation...). Or la ré-écriture pourrait se faire d’une autre manière qui garantirait que la logique de l’ordre original soit respectée...
    car ici on parle de l’ordre d’évaluation des éléments d’une expression booléenne qui lui est quand même encadré par quelques règles.

  14. #14
    Expert confirmé
    Avatar de pachot
    Homme Profil pro
    Developer Advocate YugabyteDB
    Inscrit en
    Novembre 2007
    Messages
    1 822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : Suisse

    Informations professionnelles :
    Activité : Developer Advocate YugabyteDB
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 822
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par JeitEmgie Voir le message
    on pouvait légitement s’attendre à ce qu’elle soit évaluée après les conditions des select internes
    C'est justement le point que j'essaie de préciser car c'est très dangereux. Dans un langage procédural, oui, mais pas en SQL. Il n'y a pas d'ordre d'exécution déterminé par la requête.
    Les parenthèses de la sous-requête n'impliquent pas que la sous-requête est exécutée en premier. C'est juste une factorisation pour l'écriture, comme en algèbre. Comme en maths où 2(a+b) = 2.a + 2.b

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 12/07/2019, 09h42
  2. Aide pour une sous-requète "dans" un WHERE
    Par trucmuche2005 dans le forum Requêtes
    Réponses: 3
    Dernier message: 23/06/2017, 10h45
  3. Appeler le champ d'une sous-requête where dans un select
    Par purplebamboo dans le forum PL/SQL
    Réponses: 2
    Dernier message: 24/06/2013, 15h07
  4. Besoin d'une sous requête dans la clause ORDER BY
    Par Renand dans le forum Requêtes
    Réponses: 2
    Dernier message: 23/09/2010, 14h41
  5. Réponses: 3
    Dernier message: 08/08/2006, 15h15

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo