Précédent   Forum des professionnels en informatique > Bases de données > MySQL > Débuter
Débuter Forum d'entraide pour débuter avec MySQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 01/07/2011, 11h20   #1
Futur Membre du Club
 
Homme
Étudiant
Inscription : janvier 2008
Messages : 46
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 22
Localisation : France

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : janvier 2008
Messages : 46
Points : 17
Points : 17
Par défaut Optimisation requête lourde

Bonjour,

Je suis assez embêté par le temps de chargement beaucoup trop de long de mes pages. En effet, via PHP je dois générer un tableau dynamique et afficher des informations pour chaque article dans le tableau.
Pour se faire j'ai créé une abomination que voici :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(SELECT r.article_id, a.titre, a.texte, r.ss_titre, r.lieu_id, d.date1, d.date2
FROM ARTICLES a
INNER JOIN RENSEIGNEMENTS r ON a.id = r.article_id
INNER JOIN DATES d ON r.date_id = d.id
WHERE a.edition IN ('NANCY', 'NANCY-METZ', 'NANCY-METZ-STRASB', 'NANCY-METZ-STR-DIJON', 'TTES EDITIONS')
AND a.rubrique = 'EXPOS'
AND d.date1 = ( SELECT MIN( d1.date1 ) 
                       FROM ARTICLES a1
                       INNER JOIN RENSEIGNEMENTS r1 ON a1.id = r1.article_id
                       INNER JOIN DATES d1 ON r1.date_id = d1.id
                       WHERE a1.titre = a.titre )
GROUP BY a.titre)
UNION ALL
(SELECT id, titre, texte, NULL, NULL, 9999, NULL 
FROM ARTICLES a 
WHERE id NOT IN (SELECT a.id FROM ARTICLES a, RENSEIGNEMENTS r WHERE a.id=r.article_id) 
AND a.edition IN ('NANCY', 'NANCY-METZ', 'NANCY-METZ-STRASB', 'NANCY-METZ-STR-DIJON', 'TTES EDITIONS') 
AND a.rubrique = 'EXPOS') 
ORDER BY date1
En fait certains articles n'ont pas certaines informations, du coup cela rend la requête beaucoup plus compliquée. La première partie récupère les articles classiques et les trie par date (en prenant la date minimum disponible pour l'article, car un article peut avoir plusieurs dates) et la deuxième partie récupère ceux à part, qui n'ont pas de date.

Du coup comme je n'ai pas trouvé comme faire les deux requêtes en même temps, j'ai utilisé un UNION ALL

Si quelqu'un a une idée pour rendre plus simple le bouzin je suis preneur.

Merci
Shinosha est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/07/2011, 13h20   #2
Expert Confirmé
 
Avatar de Maljuna Kris
 
Homme Avcxjo MoKo
Retraité
Inscription : novembre 2005
Messages : 2 530
Détails du profil
Informations personnelles :
Nom : Homme Avcxjo MoKo
Âge : 60

Informations professionnelles :
Activité : Retraité
Secteur : Administration - Collectivité locale

Informations forums :
Inscription : novembre 2005
Messages : 2 530
Points : 3 523
Points : 3 523
Saluton,
Il me semble qu'il te suffit de remplacer les INNER JOIN de la première requête par des LEFT JOIN et tu n'auras plus besoin de faire la deuxième requête donc l'UNION
__________________
Kie lumo eksistas ankaŭ ombro troviĝas. L.L. Zamenhof
articles : Comment émuler un tableau croisé [quasi] dynamique
et : Une énigme mathématique résolue avec MySQL
recommande l'utilisation de PDO (PHP5 Data Objects)
Maljuna Kris est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/07/2011, 14h14   #3
ced
Rédacteur/Modérateur

 
Avatar de ced
 
Homme Cédric Duprez
Inscription : avril 2002
Messages : 3 823
Détails du profil
Informations personnelles :
Nom : Homme Cédric Duprez
Âge : 36
Localisation : France, Loiret (Centre)

Informations professionnelles :
Secteur : Agroalimentaire - Agriculture

Informations forums :
Inscription : avril 2002
Messages : 3 823
Points : 6 437
Points : 6 437
Attention quand même à la condition dans le WHERE qui porte sur la date. Elle casse à elle seule l'effet des LEFT JOIN.
Il faudra peut-être la passer en condition de jointure, ou alors l'améliorer par un OR...
__________________
Rédacteur / Modérateur SGBD
Mes tutoriels et la FAQ MySQL

----------------------------------------------------
Pensez aux balises code et au tag
Je ne réponds pas aux questions techniques par message privé, les forums sont là pour ça
ced est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/07/2011, 14h22   #4
Futur Membre du Club
 
Homme
Étudiant
Inscription : janvier 2008
Messages : 46
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 22
Localisation : France

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : janvier 2008
Messages : 46
Points : 17
Points : 17
Oui c'est ce que je me disais... Qu'entends tu par conditions de jointure ou amélioration par un OR ? Tu pourrais développer ?
Shinosha est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/07/2011, 14h29   #5
ced
Rédacteur/Modérateur

 
Avatar de ced
 
Homme Cédric Duprez
Inscription : avril 2002
Messages : 3 823
Détails du profil
Informations personnelles :
Nom : Homme Cédric Duprez
Âge : 36
Localisation : France, Loiret (Centre)

Informations professionnelles :
Secteur : Agroalimentaire - Agriculture

Informations forums :
Inscription : avril 2002
Messages : 3 823
Points : 6 437
Points : 6 437
Pour que la jointure externe fonctionne, il faut passer la condition :
Code :
1
2
3
4
5
AND d.date1 = ( SELECT MIN( d1.date1 ) 
                       FROM ARTICLES a1
                       INNER JOIN RENSEIGNEMENTS r1 ON a1.id = r1.article_id
                       INNER JOIN DATES d1 ON r1.date_id = d1.id
                       WHERE a1.titre = a.titre )
dans la jointure sur la table DATES.
Ou alors, il faut modifier la condition par quelque chose comme :
Code :
1
2
3
4
5
6
7
8
AND (
    d.date1 = ( SELECT MIN( d1.date1 ) 
                       FROM ARTICLES a1
                       INNER JOIN RENSEIGNEMENTS r1 ON a1.id = r1.article_id
                       INNER JOIN DATES d1 ON r1.date_id = d1.id
                       WHERE a1.titre = a.titre )
    OR d.date1 IS NULL
)
A tester...
__________________
Rédacteur / Modérateur SGBD
Mes tutoriels et la FAQ MySQL

----------------------------------------------------
Pensez aux balises code et au tag
Je ne réponds pas aux questions techniques par message privé, les forums sont là pour ça
ced est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/07/2011, 15h00   #6
Futur Membre du Club
 
Homme
Étudiant
Inscription : janvier 2008
Messages : 46
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 22
Localisation : France

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : janvier 2008
Messages : 46
Points : 17
Points : 17
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
SELECT r.article_id, a.titre, a.texte, r.ss_titre, r.lieu_id, d.date1, d.date2
FROM ARTICLES a
LEFT JOIN RENSEIGNEMENTS r ON a.id = r.article_id
LEFT JOIN DATES d ON r.date_id = d.id
WHERE a.edition IN ('NANCY', 'NANCY-METZ', 'NANCY-METZ-STRASB', 'NANCY-METZ-STR-DIJON', 'TTES EDITIONS')
AND a.rubrique = 'EXPOS'
AND (
    d.date1 = ( SELECT MIN( d1.date1 ) 
                       FROM ARTICLES a1
                       LEFT JOIN RENSEIGNEMENTS r1 ON a1.id = r1.article_id
                       LEFT JOIN DATES d1 ON r1.date_id = d1.id
                       WHERE a1.titre = a.titre )
    OR r.article_id IS NULL
)
GROUP BY a.titre
ORDER BY date1
A partir de ça j'ai effectivement ce que je veux, le soucis c'est que les articles sans date sont au début (à cause de l'order by normal) Pour le coup je vois pas comment faire à part mettre une valeur de base dans date1 pour les articles sans date

EDIT : Merci !
Shinosha est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 02/07/2011, 13h30   #7
ced
Rédacteur/Modérateur

 
Avatar de ced
 
Homme Cédric Duprez
Inscription : avril 2002
Messages : 3 823
Détails du profil
Informations personnelles :
Nom : Homme Cédric Duprez
Âge : 36
Localisation : France, Loiret (Centre)

Informations professionnelles :
Secteur : Agroalimentaire - Agriculture

Informations forums :
Inscription : avril 2002
Messages : 3 823
Points : 6 437
Points : 6 437
Tu peux utiliser la fonction COALESCE dans le ORDER BY, en mettant une date dans le futur. Ça placera les dates à NULL en fin de liste.
COALESCE prend les arguments qui lui sont passés dans l'ordre et renvoie le premier non null. Ainsi, en mettant une date dans le futur, si la date est à NULL, c'est la date future qui est renvoyée dans le ORDER BY, et les NULL se retrouvent à la fin :
Code :
1
2
3
4
SELECT...
FROM...
WHERE...
ORDER BY COALESCE(d.date1, '2050-12-31')
Bien sûr, il faudra penser à mettre à jour ta requête en 2050
__________________
Rédacteur / Modérateur SGBD
Mes tutoriels et la FAQ MySQL

----------------------------------------------------
Pensez aux balises code et au tag
Je ne réponds pas aux questions techniques par message privé, les forums sont là pour ça
ced est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 03/07/2011, 07h14   #8
Expert Confirmé
 
Avatar de Maljuna Kris
 
Homme Avcxjo MoKo
Retraité
Inscription : novembre 2005
Messages : 2 530
Détails du profil
Informations personnelles :
Nom : Homme Avcxjo MoKo
Âge : 60

Informations professionnelles :
Activité : Retraité
Secteur : Administration - Collectivité locale

Informations forums :
Inscription : novembre 2005
Messages : 2 530
Points : 3 523
Points : 3 523
Citation:
Envoyé par ced Voir le message
Bien sûr, il faudra penser à mettre à jour ta requête en 2050
Pas de problème, Ced, si Alzheimer ou tout autre épée de Damoclès ne m'a pas dégommé d'ici là, je le lui rappellerai.
Après tout, je n'aurai qu'à peine 99 ans !
L'espoir fait vivre.
__________________
Kie lumo eksistas ankaŭ ombro troviĝas. L.L. Zamenhof
articles : Comment émuler un tableau croisé [quasi] dynamique
et : Une énigme mathématique résolue avec MySQL
recommande l'utilisation de PDO (PHP5 Data Objects)
Maljuna Kris est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 05h59.


 
 
 
 
Partenaires

Hébergement Web