Je me demandais s'il y avait un moyen d'obtenir le nombre de résultats d'une requête MySQL, et en même temps de limiter les résultats.
La façon dont la pagination fonctionne (si je comprends bien), je fais d'abord quelque chose comme
query = SELECT COUNT(*) FROM `table` WHERE `some_condition`
Après avoir obtenu le nombre_rows (requête), j'ai le nombre de résultats. Mais ensuite, pour limiter mes résultats, je dois faire une deuxième requête comme:
query2 = SELECT COUNT(*) FROM `table` WHERE `some_condition` LIMIT 0, 10
Ma question: est-il possible à la fois de récupérer le nombre total de résultats qui seraient donnés ET de limiter les résultats renvoyés dans une seule requête? Ou tout autre moyen plus efficace de le faire. Merci!
Réponses:
Non, c'est le nombre d'applications qui veulent paginer doivent le faire. Il est fiable et à l'épreuve des balles, bien qu'il fasse la requête deux fois. Mais vous pouvez mettre en cache le décompte pendant quelques secondes et cela aidera beaucoup.
L'autre façon consiste à utiliser une
SQL_CALC_FOUND_ROWS
clause puis à appelerSELECT FOUND_ROWS()
. à part le fait que vous devez mettre l'FOUND_ROWS()
appel après, il y a un problème avec ceci: il y a un bogue dans MySQL qui chatouille qui affecte lesORDER BY
requêtes, ce qui le rend beaucoup plus lent sur les grandes tables que l'approche naïve de deux requêtes.la source
Je ne fais presque jamais deux requêtes.
Renvoyez simplement une ligne de plus que nécessaire, affichez seulement 10 sur la page, et s'il y en a plus que ce qui est affiché, affichez un bouton "Suivant".
Votre requête doit revenir dans l'ordre de la plus pertinente en premier. Il y a de fortes chances que la plupart des gens ne se soucient pas d'aller à la page 236 sur 412.
Lorsque vous effectuez une recherche Google et que vos résultats ne sont pas sur la première page, vous accédez probablement à la deuxième page, et non à la neuf.
la source
COUNT
est une fonction d'agrégation. Comment renvoyer le décompte et tous les résultats en une seule requête? La requête ci-dessus ne renverra qu'une seule ligne, quel que soit leLIMIT
paramètre défini. Si vous ajoutezGROUP BY
, tous les résultatsCOUNT
serontUne autre approche pour éviter les doubles requêtes consiste à extraire d'abord toutes les lignes de la page actuelle en utilisant une clause LIMIT, puis à n'effectuer une deuxième requête COUNT (*) que si le nombre maximum de lignes a été récupéré.
Dans de nombreuses applications, le résultat le plus probable sera que tous les résultats tiennent sur une seule page, et devoir faire la pagination est l'exception plutôt que la norme. Dans ces cas, la première requête ne récupérera pas le nombre maximum de résultats.
Par exemple, les réponses à une question stackoverflow se retrouvent rarement sur une deuxième page. Les commentaires sur une réponse dépassent rarement la limite de 5 ou plus requise pour tous les montrer.
Donc, dans ces applications, vous pouvez simplement faire une requête avec une LIMIT d'abord, puis tant que cette limite n'est pas atteinte, vous savez exactement combien de lignes il y a sans avoir besoin de faire une deuxième requête COUNT (*) - ce qui devrait couvrent la majorité des situations.
la source
Dans la plupart des situations, il est beaucoup plus rapide et moins gourmand en ressources de le faire en deux requêtes distinctes que de le faire en une seule, même si cela semble contre-intuitif.
Si vous utilisez SQL_CALC_FOUND_ROWS, alors pour les grandes tables, votre requête sera beaucoup plus lente, beaucoup plus lente même que l'exécution de deux requêtes, la première avec un COUNT (*) et la seconde avec une LIMIT. La raison en est que SQL_CALC_FOUND_ROWS entraîne l'application de la clause LIMIT après l' extraction des lignes au lieu d'avant, de sorte qu'il récupère la ligne entière pour tous les résultats possibles avant d'appliquer les limites. Cela ne peut pas être satisfait par un index car il récupère réellement les données.
Si vous adoptez l'approche à deux requêtes, la première ne récupérant que COUNT (*) et ne récupérant pas réellement les données réelles, cela peut être satisfait beaucoup plus rapidement car il peut généralement utiliser des index et n'a pas à récupérer les données de ligne réelles pour chaque ligne qu'il regarde. Ensuite, la deuxième requête n'a besoin que de regarder les premières lignes $ offset + $ limit, puis de revenir.
Cet article du blog de performance MySQL explique cela plus en détail:
http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/
Pour plus d'informations sur l'optimisation de la pagination, consultez cet article et cet article .
la source
Ma réponse est peut-être en retard, mais vous pouvez ignorer la deuxième requête (avec la limite) et simplement filtrer les informations via votre script back-end. En PHP par exemple, vous pouvez faire quelque chose comme:
Mais bien sûr, lorsque vous avez des milliers d'enregistrements à prendre en compte, cela devient très vite inefficace. Le décompte pré-calculé est peut-être une bonne idée à examiner.
Voici une bonne lecture sur le sujet: http://www.percona.com/ppc2009/PPC2009_mysql_pagination.pdf
la source
la source
where
clause à la requête interne et vous obtenez le bon "total" à côté des résultatslimit
Pour tous ceux qui recherchent une réponse en 2020. Selon la documentation MySQL:
"Le modificateur de requête SQL_CALC_FOUND_ROWS et la fonction FOUND_ROWS () qui l'accompagne sont obsolètes à partir de MySQL 8.0.17 et seront supprimés dans une future version de MySQL. En remplacement, envisagez d'exécuter votre requête avec LIMIT, puis une deuxième requête avec COUNT (*) et sans LIMIT pour déterminer s'il y a des lignes supplémentaires. "
Je suppose que cela règle cela.
https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_found-rows
la source
Vous pouvez réutiliser la plupart de la requête dans une sous-requête et la définir sur un identificateur. Par exemple, une requête de film qui trouve des films contenant le tri des lettres par exécution ressemblerait à ceci sur mon site.
Notez que je ne suis pas un expert en bases de données et j'espère que quelqu'un pourra optimiser cela un peu mieux. En l'état, l'exécuter directement à partir de l'interface de ligne de commande SQL, ils prennent tous deux environ 0,02 seconde sur mon ordinateur portable.
la source
la source