Aujourd'hui, j'ai une demande concernant PostgreSQL que je ne connais pas trop, mais dont je constate que c'est bien différent de MySQL avec lequel j'ai l'habitude.
Voici une requête et le nombre d'enregistrements dans chacune des tables concernées.
SELECT
count(t1."Id") AS Number
FROM
"my_schema"."table1" t1
INNER JOIN
"my_schema"."table2" t2
ON
t1."table2_id" = t2."Id"
AND t2."IsDeleted" = false
INNER JOIN
"my_schema"."table3" t3
ON
t2."table3_id" = t3."Id"
AND t3."IsDeleted" = false
INNER JOIN
"my_schema"."table4" t4
ON
t2."table4_id" = t4."Id"
AND t4."IsDeleted" = false
INNER JOIN "my_schema"."table5" t5
ON
t4."table5_id" = t5."Id"
AND t5."IsDeleted" = false
INNER JOIN
"my_schema"."table6" t6
ON
t2."table6_id" = t6."Id"
AND t6."IsDeleted" = false
INNER JOIN
"my_schema"."table7" t7
ON
t1."table7_id" = t7. "Id"
AND t7."IsDeleted" = false
AND t7."IsActive" = true
INNER JOIN
"my_schema"."table8" t8
ON
t1."table8_id" = t8."Id"
AND t8."IsDeleted" = false
AND t8."un champ texte" = 'du texte'
AND t8."un champ date" < ?
WHERE
(t1."un champ texte" IN ('un texte', 'un autre texte'))
AND (t1."IsDeleted" = false)
-- table1 : 2'600'000 lignes
-- table2 : 1'800'000 lignes
-- table3 : 1'600'000 lignes
-- table4 : 205'000 lignes
-- table5 : 200'000 lignes
-- table6 : 1'005'000 lignes
-- table7 : 500 lignes
-- table8 : 10 lignes
La requête prend actuellement une vingtaine de secondes à retourner le résultat.
J'ai tenté de ne conserver que les jointures sur les tables 7 et 8, je descends à 6 secondes.
Je ne suis donc pas familier de PostgreSQL, ni des performances qu'on pourrait attendre de ce genre de requête avec ce volume de données. La seule chose que je me permets d'extrapoler est que c'est une simple requête qui compte et que, ayant en vue la même (cette fois obligatoirement avec toutes les tables) mais pour sélectionner des éléments, le temps de requête risque d'être plus conséquent, et ça me semble un peu long quand même.
J'ai mis des index sur les colonnes de clés étrangères (je ne peux pas mettre une vraie contrainte, la table est de toute manière en lecture seule et alimentée sans prendre cela en compte), mais apparemment cela n'impacte pas vraiment le temps de requête — je n'ai pas mesuré avant/après, je pensais qu'il y aurait de toute manière amélioration.
Du peu que j'ai compris, mettre des index à tort et à travers peut se révéler contre-productif, et j'en ai peut-être déjà mis là où il n'y aurait pas nécessairement besoin.
J'ai pris le temps d'utilser EXPLAIN ANALYSE, mais je ne saurais même pas comment utiliser le résultat de l'équivalent MySQL, donc ça ne m'avance malheureusement pas trop.
Du coup, trois questions déjà :
au vu du volume de données, est-ce que 20 secondes est quelque chose de normal ?
si non, est-ce que d'ajouter des index précis serait pertinent ?
Le cas échéant, lesquels ?
J'ai des index sur les colonnes contenant les IDs étrangers et j'ai tenté d'ajouter des index sur les paires (IsDeleted, Id) — dans cet ordre précisément, en pensant que ça pourrait aider sur les jointures, mais apparemment cela ne change pas grand chose. Tu préconiserais de mettre deux index séparés ?
Je n'ai pas mis d'index sur table7."IsActive", je me disais que vu le volume, le gain ne serait pas le plus pertinent.
Peux-tu retirer tous les index ( sauf clé primaire et clé étrangère), exécuter ta requête entière avec EXPLAIN et nous poster le retour du plan d'exécution ?
Malheureusement je ne peux pas retirer les index sur les paires de colonnes aussi facilement, donc là c'est avec eux. Je reviendrai quand ç'aura été possible de les enlever.
Ce qui me paraît bizarre, c'est qu'il n'y a aucune référence à d'éventuels index ... comme si aucun des index n'étaient utilisés pour cette requête ...
T'est-il possible de nous faire un dump SQL de ta base en l'état (au moins les CREATE TABLE des 8 tables en jeu) ?
Ymox a écrit:
je ne peux pas retirer les index sur les paires de colonnes aussi facilement,
Cela est chelou aussi ... Tu as un erreur ? Le DROP INDEX ne fonctionne pas ?
T'est-il possible de nous faire un dump SQL de ta base en l'état (au moins les CREATE TABLE des 8 tables en jeu) ?
Je peux probablement fournir une structure anonymisée et épurée, mais pas de données ni la liste complète des colonnes. En revanche, je peux en fournir le nombre pour chaque table.
Benzouye a écrit:
Cela est chelou aussi ...
Pas tant que ça, c'est une table gérée par quelqu'un d'autre, je n'y ai qu'un accès limité, apparemment qu'en lecture. Donc je passe par quelqu'un d'autre pour manipuler ces index.
Edit
En attendant, j'aimerais préciser que les IDs sont des chaînes de 18 caractères, et non des entiers, et apparemment toutes dans des champs text.
Aïe ... c'est chaud de maintenir cette conception ... dette technique quand tu nous tiens
Ymox a écrit:
mettre des index sur les booléens ne semble pas impacter grand chose ;
En fait c'est normal, sur un booléen tu as une cardinalité de 2 donc peu d'intérêt sur l'index ...
Après, c'est fou que ce soit la jointure t4->t5 qui soit la plus gourmande du plan d'exécution alors que ce ne sont pas les plus gros volumes ...
Ce qui peut être intéressant à regarder c'est l'impact de la clause WHERE texte IN(...) car elle est placée sur la table la plus volumineuse. Si tu la retires l'impact est-il sensible ? Si oui, il faudrait peut-être regarder pour faire de la recherche FULLTEXT ...
Ce qui peut être intéressant à regarder c'est l'impact de la clause WHERE texte IN(...) car elle est placée sur la table la plus volumineuse. Si tu la retires l'impact est-il sensible ?
Je passe à 36 secondes. Là aussi, c'est un champ text. En fait, les types ne sont pas super variés : text, double precisionboolean et timestamp with time zone (une joie de travailler avec ces derniers…)
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.