web-dev-qa-db-fra.com

Est-il préférable de séparer une grande requête en plusieurs requêtes plus petites?

Il y a des situations qui nécessitent d'avoir une très grosse requête joignant plusieurs tables avec des instructions de sous-sélection pour produire les résultats souhaités.

Ma question est la suivante: devrions-nous envisager d'utiliser plusieurs requêtes plus petites et intégrer les opérations logiques dans la couche application en interrogeant la base de données en plusieurs appels ou est-il préférable de les avoir toutes en une seule fois?
Par exemple, considérez la requête suivante:

SELECT *
FROM   `users`
WHERE  `user_id` IN (SELECT f2.`friend_user_id`
                     FROM   `friends` AS f1
                            INNER JOIN `friends` AS f2
                              ON f1.`friend_user_id` = f2.`user_id`
                     WHERE  f2.`is_page` = 0
                            AND f1.`user_id` = "%1$d"
                            AND f2.`friend_user_id` != "%1$d"
                            AND f2.`friend_user_id` NOT IN (SELECT `friend_user_id`
                                                            FROM   `friends`
                                                            WHERE  `user_id` = "%1$d"))
       AND `user_id` NOT IN (SELECT `user_id`
                             FROM   `friend_requests`
                             WHERE  `friend_user_id` = "%1$d")
       AND `user_image` IS NOT NULL
ORDER  BY Rand() 
LIMIT %2$d

Quelle est la meilleure façon de procéder?

13
Hamed Momeni

Je vais être en désaccord sur les requêtes volumineuses et compliquées avec datagod ici. Je ne les vois comme des problèmes que s'ils sont désorganisés. En termes de performances, celles-ci sont presque toujours meilleures car le planificateur a beaucoup plus de liberté pour récupérer les informations. Cependant, les requêtes volumineuses doivent être écrites dans un souci de maintenabilité. En général, j'ai trouvé que le SQL simple et bien structuré est facile à déboguer même lorsqu'une seule requête se poursuit pour plus de 200 lignes. En effet, vous avez généralement une assez bonne idée du type de problème auquel vous êtes confronté, il n'y a donc que quelques zones de la requête que vous devez vérifier.

Les problèmes de maintenance, IME, surviennent lorsque la structure de SQL tombe en panne. Les requêtes longues et complexes dans les sous-sélections nuisent à la lisibilité et au dépannage, tout comme les vues en ligne, et ces deux éléments doivent être évités dans les requêtes longues. Au lieu de cela, utilisez des VUES si vous le pouvez (notez que si vous êtes sur MySQL, les vues ne fonctionnent pas très bien, mais sur la plupart des autres bases de données, elles le font), et utilisez des expressions de table communes là où celles-ci ne fonctionnent pas (MySQL ne prend pas en charge ces btw).

Les longues requêtes complexes fonctionnent plutôt bien à partir d'un cas de maintenabilité et de performances où vous gardez vos clauses where simples et où vous faites autant que vous le pouvez avec des jointures au lieu de sous-sélections. Le but est de faire en sorte que "les enregistrements ne s'affichent pas" vous donne quelques endroits très spécifiques dans la requête à vérifier (est-il supprimé dans une jointure ou filtré dans une clause where?) Et donc l'équipe de maintenance peut réellement maintenir les choses.

En ce qui concerne l'évolutivité, gardez à l'esprit que plus la flexibilité du planificateur est grande, c'est aussi une bonne chose ...

Edit: Vous mentionnez qu'il s'agit de MySQL, il est donc peu probable que les vues fonctionnent aussi bien et les CTE sont hors de question. De plus, l'exemple donné n'est pas particulièrement long ou complexe, ce n'est donc pas un problème.

14
Chris Travers

En tant que personne qui doit prendre en charge/nettoyer ces requêtes volumineuses et compliquées, je dirais qu'il est bien préférable de les séparer en plusieurs petits morceaux faciles à comprendre. Ce n'est pas nécessairement meilleur du point de vue des performances, mais vous donnez au moins à SQL une meilleure chance de trouver un bon plan de requête.

Rendez la vie plus facile aux gens qui vous suivent et ils vous diront de bonnes choses. Rendez-le dur et ils vous maudiront.

8
datagod

Mes 2 cents sur les performances et l'évolutivité des requêtes de 2 mots clés:

Query-Performance: Le parallélisme SQL Server fait déjà un très bon travail en décomposant les requêtes en recherches multi-threads, donc je ne sais pas dans quelle mesure vous améliorerez les performances des requêtes en le faisant pour Serveur SQL. Cependant, vous devrez regarder le plan d'exécution pour voir le degré de parallélisme que vous obtenez lorsque vous l'exécutez et comparer les résultats dans les deux sens. Si vous finissez par avoir à utiliser un indice de requête pour obtenir des performances identiques ou meilleures, alors l'OMI ne vaut pas la peine car l'indice de requête pourrait ne pas être optimal plus tard.

évolutivité: La lecture des requêtes peut être plus facile, comme l'indique le code de données, et la décomposer en requêtes distinctes est logique si vous pouvez également utiliser vos nouvelles requêtes dans d'autres domaines, mais si vous n'allez pas les utiliser pour les autres appels également, il y aura encore plus de processus stockés à gérer pour 1 tâche, et IMO ne contribuerait pas à l'évolutivité.

5
Ali Razeghi

Parfois, il n'y a pas d'autre choix que de diviser la requête grande/complexe en petites requêtes. La meilleure façon de déterminer cela serait d'utiliser l'instruction EXPLAIN avec l'instruction SELECT. Le nombre de traces/analyses que votre base de données va effectuer pour récupérer vos données est le produit des valeurs de "lignes" renvoyées par votre requête EXPLAIN. Dans notre cas, nous avons eu une requête joignant 10 tables. Pour un record particulier, la trace s'élevait à 409M qui bloguait notre base de données et poussait notre utilisation CPU de notre serveur DB plus de 300%. Nous avons pu récupérer les mêmes informations en fractionnant les requêtes beaucoup plus rapidement.

Donc, en bref, dans certains cas, le fractionnement d'une requête complexe/volumineuse est logique, mais dans d'autres, cela peut entraîner de nombreux problèmes de performances ou de maintenance et cela doit être traité au cas par cas.

2
user140665