Bonjour,
j'ai une certain requête, assez longue (et ce n'est que la sous requête d'une autre ) mais que j'ai fait le plus compréhensible possible ....
Je ne vais pas m'attarder plus, la voici :


Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT * FROM(SELECT *, seances.id AS id_seance, activities.id AS id_activity, MAX(nb_real) OVER(PARTITION BY realisations.seance) AS nb_real_max,modules.cycle AS module_cycle, seances.repetition AS module_repetition,  modules.id AS id_mod, ROW_NUMBER() OVER(PARTITION BY modules.id ORDER BY realisations.nb_real ASC, ordre ASC) AS rn FROM modules
INNER JOIN activities ON activities.id_module = modules.id
INNER JOIN seances ON seances.id_module=modules.id
INNER JOIN j_seances_niveaux js ON js.id_seance=seances.id AND id_niveau = 11
INNER JOIN j_membres_modules jm ON jm.membre = 1 AND jm.module = modules.id
LEFT JOIN realisations ON realisations.activity = activities.id AND member = 1
LEFT JOIN provocations ON provocations.provoque = activities.id
WHERE (activities.type_freq=3 OR activities.type_freq=1) -- filtre de la fréquence
AND (modules.cycle='1' OR (date_start<NOW() AND date_end < NOW())) -- filtre pour la date ...
AND (jm.report IS NULL OR jm.report <= NOW()) -- en faisant attention aux reports éventuels
) AS tmp
WHERE rn = 1
AND (tmp.module_cycle='1' OR nb_real_max IS NULL OR nb_real_max < tmp.module_repetition) -- filtre pour la répétition
bon, c'est très bien, mais j'ai néanmoins remarqué que si au lieu de retourner tout au lieu de juste un champs, ça ne prenais que 100 ms. Avec cette requête qui renvoie tous les résultats, ça prend 700 ms.

Alors, j'ai eu une idée : au lieu de tout retourner, pourquoi ne pas retourner seulement quelques champs, et faire ensuite des INNER JOIN pour récupérer les même données ? Et ça donne ceci :

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
16
SELECT * FROM(SELECT seances.id AS id_seance, activities.id AS id_activity, MAX(nb_real) OVER(PARTITION BY realisations.seance) AS nb_real_max,modules.cycle, seances.repetition,  modules.id AS id_mod, ROW_NUMBER() OVER(PARTITION BY modules.id ORDER BY realisations.nb_real ASC, ordre ASC) AS rn FROM modules
INNER JOIN activities ON activities.id_module = modules.id
INNER JOIN seances ON seances.id_module=modules.id
INNER JOIN j_seances_niveaux js ON js.id_seance=seances.id AND id_niveau = 11
INNER JOIN j_membres_modules jm ON jm.membre = 1 AND jm.module = modules.id
LEFT JOIN realisations ON realisations.activity = activities.id AND member = 1
LEFT JOIN provocations ON provocations.provoque = activities.id
WHERE (activities.type_freq=3 OR activities.type_freq=1) -- filtre de la fréquence
AND (modules.cycle='1' OR (date_start<NOW() AND date_end < NOW())) -- filtre pour la date ...
AND (jm.report IS NULL OR jm.report <= NOW()) -- en faisant attention aux reports éventuels
) AS tmp
INNER JOIN modules ON modules.id = tmp.id_mod
INNER JOIN activities ON activities.id = id_activity
INNER JOIN seances ON seances.id = id_seance 
WHERE rn = 1
AND (tmp.cycle='1' OR nb_real_max IS NULL OR nb_real_max < tmp.repetition) -- filtre pour la répétition
temps d'exécution : ... 150 ms !!!
En fait, je ne m'y attendais pas
au fait, à quoi c'est dû ? je crois deviner à moitié, mais sans plus .... Je suppose que au plus la masse de données à traiter dans les fonction analytique sont faibles, au plus c'est rapide, même si toutes les données ne joue pas dans ces fonctions analytique ... Je me trompe ?

Et sinon, verriez-vous d'autre amélioration à apporter ?

Quelque infos qui pourrais servir :

les tables les plus lourde sont :

seance (~ 20 000 lignes)
realisations (très lourde, de 5 000 à 1 000 000 de lignes, et environ 10 000 pour un même membre (cf champ realisations.member))

Merci d'avance.

PS

Peut-être avez vous remarqué que dans la deuxième requête, je ne récupère pas les résultats des tables provocations et realisations, mais même si je les récupère, ça fait en tout 160 ms, presque rien quoi.