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

Langage SQL Discussion :

PostgresSQL : decoupage d'une requête avec des BETWEEN pour optimiser la requête.


Sujet :

Langage SQL

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2009
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 22
    Points : 23
    Points
    23
    Par défaut PostgresSQL : decoupage d'une requête avec des BETWEEN pour optimiser la requête.
    Bonjour à tous.

    Voici la requête de départ :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT  t1.anode, sum(t2.size)
    FROM t4, t3, t2, t1
    WHERE
        t4.onode = t1.onode AND
        t3.inode = t4.inode AND
        t3.snode = t2.snode
    GROUP BY t1.anode;
    Elle fonctionne bien sur les BDD de petite taille, mais sur les très gros volumes il y a un temps important avant d’obtenir la réponse.

    On me demande de tester un découpage de la requête pour vérifier que ce n'est pas plus rapide.
    Je me suis dit facile ... je fais une boucle. Puis je m'aperçois que : faire un tableau double entré avec un "if exit la valeur" pour stocker le résultat d'une requête de plusieurs lignes me pose un gros problème.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT  t1.anode, sum(t2.size)
    FROM t4, t3, t2, t1
    WHERE
        t4.onode = t1.onode AND
        t3.inode = t4.inode AND
        t3.snode = t2.snode AND
        t2.snode BETWEEN Var_Min_snode AND Var_Min_snode + Var_count_Division
    GROUP BY t1.anode;
    Si quelqu'un peut me donner des pistes ?

  2. #2
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 133
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 133
    Points : 38 556
    Points
    38 556
    Billets dans le blog
    9
    Par défaut
    Bonjour,

    Plutôt que de faire le produit cartésien des 4 tables puis d'appliquer une restriction sur le résultat, il est préférable d'utiliser des jointures normalisées avec l'opérateur JOIN :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    SELECT t1.anode
         , sum(t2.size)
    FROM t4
    inner join t3 
       on t3.inode = t4.inode
    inner join t2
       on t2.snode = t3.snode
    inner join t1
       on t1.onode = t4.onode
    GROUP BY t1.anode;

    Si ce n'est toujours pas suffisamment performant, vérifiez que les critères de jointure sont bien de même type et de même longueur dans chaque table et qu'ils sont bien indexés.

    Les SGBD relationnels sont d'autant plus performants qu'on utilise des requêtes ensemblistes : faire 3 requêtes au lieu d'une est une mauvaise solution qui au mieux ne changera rien et au pire augmentera le temps total d'exécution

  3. #3
    Expert éminent
    Avatar de Séb.
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    5 098
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 098
    Points : 8 207
    Points
    8 207
    Billets dans le blog
    17
    Par défaut
    Je rejoins escartefigue sur le JOIN à utiliser.

    Elle fonctionne bien sur les BDD de petite taille, mais sur les très gros volumes il y a un temps important avant d’obtenir la réponse.
    C'est possible d'avoir une idée des chiffres ?
    Petite taille : combien de lignes dans les tables ?
    Très gros volume : combien de lignes ?
    Temps important : de combien à combien ?

    Parce que bon, le diag peut aller de "c'est normal que la requête prenne quelques secondes si tu as quelques centaines de millions de lignes à brasser" à "en effet, il n'est pas normal que le temps d'exécution soit multiplié si tu passes de 50 k à 1 M de lignes"
    Un problème exposé clairement est déjà à moitié résolu
    Keep It Smart and Simple

  4. #4
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Citation Envoyé par escartefigue Voir le message
    Plutôt que de faire le produit cartésien des 4 tables puis d'appliquer une restriction sur le résultat
    C'est surtout conceptuel, le plan d'exécution sera le même. Mais oui c'est une bonne pratique.

    Citation Envoyé par escartefigue Voir le message
    Si ce n'est toujours pas suffisamment performant, vérifiez que les critères de jointure sont bien de même type et de même longueur dans chaque table et qu'ils sont bien indexés.
    Compte-tenu qu'il n'y a aucun filtre les index n'ont ici probablement aucun intérêt et au contraire il faut vérifier qu'ils ne sont pas utilisés.

    Citation Envoyé par escartefigue Voir le message
    Les SGBD relationnels sont d'autant plus performants qu'on utilise des requêtes ensemblistes : faire 3 requêtes au lieu d'une est une mauvaise solution qui au mieux ne changera rien et au pire augmentera le temps total d'exécution
    Faux. À partir du moment où l'exécution d'une requête consomme plus de RAM que ce qui est disponible, le SGBD va écrire sur disque pour pouvoir continuer ses opérations.
    Si le découpage permet de rester en RAM, 3 * 1/3 sera plus rapide que 1 * 1.

    La difficulté résidant dans trouver le bon découpage... et bien entendu que le résultat le permette.

  5. #5
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 133
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 133
    Points : 38 556
    Points
    38 556
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par Waldar Voir le message
    C'est surtout conceptuel, le plan d'exécution sera le même. Mais oui c'est une bonne pratique.
    En fait, ca dépend des optimiseurs, au mieux c'est neutre, au pire, c'est bien une restriction post produit cartésien qui est appliquée


    Citation Envoyé par Waldar Voir le message
    Compte-tenu qu'il n'y a aucun filtre les index n'ont ici probablement aucun intérêt et au contraire il faut vérifier qu'ils ne sont pas utilisés.
    Il n'y a plus de restriction (WHERE) si on écrit les jointures proprement, mais les index sont ici utilisés pour les jointures


    Citation Envoyé par Waldar Voir le message
    Faux. À partir du moment où l'exécution d'une requête consomme plus de RAM que ce qui est disponible, le SGBD va écrire sur disque pour pouvoir continuer ses opérations. Si le découpage permet de rester en RAM, 3 * 1/3 sera plus rapide que 1 * 1.

    La difficulté résidant dans trouver le bon découpage... et bien entendu que le résultat le permette.
    En effet, je n'avais pas pensé à ce cas de débordement de la RAM, ok en effet si c'est le cas.

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2009
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 22
    Points : 23
    Points
    23
    Par défaut Merci pour vos réponses
    Citation Envoyé par escartefigue Voir le message
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT t1.anode, sum(t2.size) FROM t4
    inner join t3 on t3.inode = t4.inode
    inner join t2 on t2.snode = t3.snode
    inner join t1 on t1.onode = t4.onode
    GROUP BY t1.anode;
    J'ai testé les 3 types de requêtes avec "EXPLAIN", elles ont le même comportement et le même temps d’exécution sur les petites tables.
    Liste des 3 types de jointures:
    1 - jointure dans le FROM séparé par des virgules
    2 - jointure avec le mot clé "join"
    3 - jointure avec le mot clé "WITH"

    Citation Envoyé par Séb. Voir le message
    Petite taille : combien de lignes dans les tables ?
    Très gros volume : combien de lignes ?
    Temps important : de combien à combien ?
    Petite taille : 52 000 000 row pour t2 & t4 et t3 40 000 000
    Très gros volume : 609 000 000 row pour t2 & t4 et t3 560 000 000
    Temps important : 4h à 7h selon les machines (de 16 à 64 cores et de la ram en suffisance, mais disque non-SSD)

    Pour information : les temps sont analogues sur maxDB, mais dans le passé l'éclatement des requêtes sur maxDB a montré de beaux gains de performance.


    Je suis vos réponses et je vais continuer les tests, car je souhaite apprends.
    Je ne rentre pas dans les détails, mais je n'ai plus la réservation de ma machine de test. J'ai donc finalisé le POC en me rabattant sur un script Perl pour faire le taf.

    Une machine a été préparée avec une base 1.7To pour faire une flopée de tests de performance.

    Pour tout vous dire, j'ai commencé un script qui utilise une table temporaire pour stocker le résultat de chaque boucle. Puis pour optenir le resultat, un:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT anode, sum(size) FROM TEMPTABLE GROUP BY anode;
    que je finirais ce week-end pour vérifier la différence du temps de traitement du script Perl et de la fonction ....

  7. #7
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 133
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 133
    Points : 38 556
    Points
    38 556
    Billets dans le blog
    9
    Par défaut
    Quel types d'accès l'explain donne -t-il pour chacune des tables ?

  8. #8
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 763
    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 : 21 763
    Points : 52 554
    Points
    52 554
    Billets dans le blog
    5
    Par défaut
    Déjà il faudrait savoir de quelle(s) table(s) viennent les colonnes Var_Min_snode, Var_Min_snode, Var_count_Division car je soupçonne une jointure triangulaire !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT  t1.anode, sum(t2.size)
    FROM    t4 
            JOIN t1 ON t4.onode = t1.onode
            JOIN t3 ON t3.inode = t4.inode
            JOIN t2 ON t3.snode = t2.snode
    WHERE   t2.snode BETWEEN ???.Var_Min_snode 
                         AND ???.Var_Min_snode + ???.Var_count_Division
    GROUP   BY t1.anode;
    Dans un tel cas aucune optimisation n'est possible et il est probable que le modèle de données soit foireux (irrespect des formes normales). Donc, remodéliser la base de données...

    Autre solution, utilisée une vue matérialisée. Mais à ce jeux là PostGreSQL est assez mauvais...

    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/ * * * * *

  9. #9
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Je testerai aussi une dernière requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    with cte_t2_agg (snode, size) as
    (
      select snode, sum(size)
        from t2
    group by snode
    )
      select t1.anode, sum(t2.size)
        from t1
        join t4               on t4.onode = t1.onode
        join t3               on t3.inode = t4.inode
        join cte_t2_agg as t2 on t2.snode = t3.snode
    group by t1.anode;

Discussions similaires

  1. [2012] Créer une table avec des commentaires pour chaque champ
    Par clluciole dans le forum Développement
    Réponses: 1
    Dernier message: 30/09/2015, 15h58
  2. Réponses: 3
    Dernier message: 19/06/2015, 00h23
  3. Réponses: 2
    Dernier message: 25/05/2011, 17h07
  4. Réponses: 4
    Dernier message: 22/11/2007, 19h23
  5. Créer une vue avec des requêtes UNION ?
    Par webtheque dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 04/04/2005, 12h37

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