Jump to content
Sign in to follow this  
Sarc

[SQL] Une requête foireuse

Rate this topic

Recommended Posts

Bonjour à tous,

J'ai une requête qui me pose problème : 4 secondes pour être exécutée ! :(

 SELECT DISTINCT
SQL_CALC_FOUND_ROWS a.pleindechamps, c.dautrechamps
FROM matab a, matab2 b
WHERE (
(
b.champ2 = 53
AND b.champ = a.champ
AND b.champ3 = 1
)
OR (
a.champ = 53
)
)
ORDER BY a.date DESC
LIMIT 0 , 15

Les cardinalités des deux tables sont de l'ordre de quelques milliers. Apparemment, il n'arriverait pas à optimiser son algorithme pour s'éviter de toutes les parcourir, et donc il a quelques millions de tuples à parcourir...

En virant l'order by et le SQL_CALC_FOUND_ROWS, le problème est résolu.

Je me dis que j'ai peut-être mal foutu mes index, et que je n'ai pas trop aidé le serveur SQL, mais j'ai du mal à voir où ça bloque... J'ai un index sur (champ2, champ) mais ça ne lui simplifie pas la vie..

Avez-vous des idées de pistes à explorer ?

Share this post


Link to post
Share on other sites

Bon bah je me réponds à moi-même, juste après avoir posté, j'ai testé un truc : séparer ma requête en deux requêtes. La première condition (ci-dessous) semble faire monter en exponentiel le temps de calcul, pour une raison que j'ignore...

(
b.champ2 = 53
AND b.champ = a.champ
AND b.champ3 = 1
)
OR (
a.champ = 53
)

Si d'aucuns ont une idée de pourquoi, en théorie quantique des SGBD, cette condition idiote ralentit à ce point la requête... En séparant en deux requêtes, je peux descendre à quelques millisecondes maximum...

Share this post


Link to post
Share on other sites

En splittant une requête, la mise en cache est souvent plus efficace. Ceci dit le rapport de perf (4:1 apparemment) me paraît trop important pour que ça soit la seule raison.

Ça peut parfois provenir de pk mal placées.

Share this post


Link to post
Share on other sites

Euh... Tu as relu ta requête? Je ne crois pas que ça fasse ce que tu veux, et il est assez normal que ça prenne trois plombes. Tu lui dis que tu veux:

- les combinaisons de lignes de a et b où b.champ=a.champ et quelques conditions sur b

- les combinaisons de lignes de a et b avec une condition sur a

En supposant qu'il y ait un lien 1-1 entre a et b avec la première condition, cette partie-là est relativement simple. La deuxième par contre signifie que pour chaque ligne de a qui correspond à la condition, tu veux toutes les lignes de b (jointure non qualifiée). Bref, c'est un peu du même niveau que select * from a,b sans aucune condition, ça renvoie forcément beaucoup de lignes et ça prend tout plein de temps, de mémoire, tout ça.

Bref, sauf cas très particulier, il est vraisemblable que ta requête soit fausse. Soit il manque là aussi un a.champ=b.champ, soit dans ce cas-là tu ne veux que les valeurs de a et tu ignores celles de b et dans ce cas il vaut effectivement probablement mieux faire deux requêtes séparées (tu dois pouvoir t'en tirer avec un UNION, mais ça va compliquer la requête).

Jacques.

Share this post


Link to post
Share on other sites

Sur la première condition (du OR), il y a une relation 1-n, mais en effet, prise à part, cette requête est rapide. Sur la deuxième condition du OR, je récupère exactement le même type d'objets, mais je n'ai aucune condition sur b... Et comme je ne sélectionne aucun champ du b, je ne pensais pas qu'il faisait tous les tuples possibles quand même.

En fait, la première condition vérifie qu'un champ existe dans le b, et la deuxième n'a pas besoin de vérifier parce que j'ai déjà le champ qui me va dans a. Difficile à expliquer comme ça, mais c'est l'idée.

Ma question, maintenant, c'est pourquoi un SGBD est pas foutu de comprendre que "SELECT a.champ FROM table a, table2 b WHERE a.id=truc" est équivalent à "SELECT a.champ FROM table a WHERE a.id=truc" ?

Ça me paraît incohérent.

Share this post


Link to post
Share on other sites

Non, c'est complètement normal. Si tu fais un select de plusieurs tables, par défaut tu as un produit cartésien (toutes les lignes de A x toutes les lignes de B), qui est ensuite "réduit" par les conditions que tu donnes (ou pas, si tu n'en donnes pas). Dans ton cas, tu ne qualifies ou sélectionnes peut-être aucun champ de b, mais tu lui demandes des lignes de b (sinon pourquoi tu le mettrais dans ta liste des tables?). C'est un peu comme si tu nous disais que si tu fais un "select * from table", vu que tu ne qualifies aucun champ, il ne devrait rien renvoyer...

Si tu n'es intéressé que par les colonnes de a (et que b ne sert qu'à qualifier dans certains cas), plusieurs solutions:

select a.colonnes from a,b where (a.col=b.col and conditions_sur_B) union all select a.colonnes from a where conditions_sur_a

select a.colonnes from a where (a.col in (select col from b where conditions_sur_B) or conditions_sur_a)

Ca peut être utile de faire appel à des jointures explicites (select ... from a join b on (condition_de_jointure) where autres_conditions) si ça t'aide à mieux formaliser ce que tu veux.

Jacques.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×
×
  • Create New...