Développement #98514
/api/users/: problème de requêtes N+1 sur les rôles
0%
Description
ApiUsersDirectory._q_index() répète les requêtes de récupération des rôles pour chaque utilisateur, puis encore une fois dans can_go_in_backoffice() lors de la génération des variables de substitution, il faudrait les pré-charger avant de générer la liste des utilisateurs.
In [2]: import pstats In [3]: import cProfile In [4]: from unittest.mock import Mock In [5]: from quixote import get_publisher In [6]: from wcs.api import ApiUsersDirectory In [7]: pub = get_publisher() In [8]: pub._set_request(Mock(form={})) In [9]: with cProfile.Profile() as pr: ...: len(ApiUsersDirectory()._q_index()) ...: In [13]: pstats.Stats(pr).sort_stats(pstats.SortKey.TIME).print_stats(40) 7226497 function calls (7188651 primitive calls) in 8.193 seconds Ordered by: internal time List reduced from 726 to 40 due to restriction <40> ncalls tottime percall cumtime percall filename:lineno(function) 9455 3.245 0.000 3.300 0.000 {function LoggingCursor.execute at 0x7f5ddffdbce0} 25963/3709 0.286 0.000 2.469 0.001 /usr/lib/python3/dist-packages/django/template/base.py:426(parse) 55635 0.277 0.000 0.629 0.000 /usr/lib/python3/dist-packages/django/template/base.py:746(__init__) 51926 0.276 0.000 1.216 0.000 /usr/lib/python3/dist-packages/django/template/base.py:624(__init__) 111270 0.148 0.000 0.216 0.000 /usr/lib/python3/dist-packages/django/template/base.py:351(create_token) 3709 0.132 0.000 0.648 0.000 /usr/lib/python3/dist-packages/wcs/formdata.py:50(get_dict_with_varnames) 81598 0.127 0.000 0.161 0.000 /usr/lib/python3/dist-packages/django/utils/text.py:325(smart_split) 59344 0.125 0.000 0.316 0.000 /usr/lib/python3/dist-packages/django/utils/functional.py:224(wrapper) 3709 0.109 0.000 0.404 0.000 /usr/lib/python3/dist-packages/django/template/base.py:337(tokenize) 14836 0.101 0.000 0.212 0.000 /usr/lib/python3/dist-packages/unidecode/__init__.py:117(_unidecode) 89016 0.097 0.000 0.124 0.000 /usr/lib/python3/dist-packages/django/template/base.py:493(extend_nodelist) 22254 0.089 0.000 1.809 0.000 /usr/lib/python3/dist-packages/django/template/defaulttags.py:906(do_if) 29672 0.083 0.000 0.483 0.000 /usr/lib/python3/dist-packages/wcs/qommon/misc.py:176(simplify) 222542 0.081 0.000 0.109 0.000 /usr/lib/python3.11/enum.py:192(__get__) 174323 0.076 0.000 0.093 0.000 /usr/lib/python3/dist-packages/unidecode/__init__.py:81(_get_repl_str) 617370 0.075 0.000 0.075 0.000 {built-in method builtins.isinstance} 9454 0.070 0.000 3.510 0.000 /usr/lib/python3/dist-packages/wcs/sql.py:2248(get) 3709 0.064 0.000 2.581 0.001 /usr/lib/python3/dist-packages/wcs/users.py:246(get_substitution_variables) 33381 0.063 0.000 0.102 0.000 /usr/lib/python3/dist-packages/django/template/base.py:816(_resolve_lookup) 315796 0.060 0.000 0.060 0.000 {method 'startswith' of 'str' objects} 77889 0.060 0.000 0.078 0.000 /usr/lib/python3/dist-packages/django/utils/functional.py:244(inner) 22254 0.059 0.000 0.748 0.000 /usr/lib/python3/dist-packages/django/template/smartif.py:153(__init__) 598675 0.059 0.000 0.059 0.000 {method 'append' of 'list' objects} 118688 0.058 0.000 0.068 0.000 /usr/lib/python3/dist-packages/django/utils/functional.py:226(<genexpr>) 22254 0.056 0.000 0.236 0.000 /usr/lib/python3/dist-packages/django/template/base.py:316(split_contents) 55635 0.054 0.000 0.055 0.000 /usr/lib/python3/dist-packages/django/utils/text.py:376(unescape_string_literal) 63053 0.049 0.000 0.049 0.000 {method 'sub' of 're.Pattern' objects} 81606 0.046 0.000 0.046 0.000 {method 'update' of 'dict' objects} 1 0.046 0.046 0.046 0.046 /usr/lib/python3.11/json/encoder.py:205(iterencode) 74180 0.045 0.000 0.045 0.000 {method 'finditer' of 're.Pattern' objects} 3709 0.045 0.000 0.381 0.000 /usr/lib/python3/dist-packages/django/template/base.py:934(render) 9454 0.044 0.000 0.070 0.000 /usr/lib/python3/dist-packages/wcs/sql.py:2742(_row2ob) 33381 0.044 0.000 0.204 0.000 /usr/lib/python3/dist-packages/django/template/base.py:668(resolve) 133524 0.043 0.000 0.058 0.000 /usr/lib/python3/dist-packages/django/template/base.py:546(next_token) 63053 0.041 0.000 0.144 0.000 /usr/lib/python3.11/re/__init__.py:178(sub) 174224/174197 0.041 0.000 0.041 0.000 {built-in method builtins.getattr} 59375 0.041 0.000 0.109 0.000 {built-in method builtins.any} 3709 0.041 0.000 0.041 0.000 {method 'split' of 're.Pattern' objects} 63058 0.040 0.000 0.057 0.000 /usr/lib/python3.11/re/__init__.py:272(_compile) 37090 0.039 0.000 0.661 0.000 /usr/lib/python3/dist-packages/django/template/smartif.py:173(translate_token)
L'initialisation répétée du template semble aussi un peu coûteuse.
Associated revisions
misc: move template constructor out of loop (#98514)
misc: prefetch roles in user datasources (#98514)
History
Updated by Frédéric Péters 2 months ago
Alternativement on pourrait dégager tout ça, /api/users/ ne devrait plus être utilisé, la seule utilité qui reste est la correspondance id wcs → uuid authentic.
Updated by Robot Gitea 2 months ago
- Status changed from Nouveau to En cours
Benjamin Dauvergne (bdauvergne) a ouvert une pull request sur Gitea concernant cette demande :
- URL : https://git.entrouvert.org/entrouvert/wcs/pulls/1955
- Titre : WIP: améliorer les performances de /api/users/ et /api/users/xxx/ (#98514)
- Modifications : https://git.entrouvert.org/entrouvert/wcs/pulls/1955/files
Updated by Benjamin Dauvergne 2 months ago
Frédéric Péters a écrit :
Alternativement on pourrait dégager tout ça, /api/users/ ne devrait plus être utilisé, la seule utilité qui reste est la correspondance id wcs → uuid authentic.
Sûr, néanmoins je vois un autre endroit ou ce problème d'appels N+1 doit se produire c'est dans les sources de donnée sur les utilisateurs, là aussi user.get_substitution_variables() est appelé à répétition sur une liste d'utilisateurs, la possibilité de pré-charger les rôles pourra y être réutilisée.
Updated by Robot Gitea about 1 month ago
- Status changed from Solution proposée to En cours
Frédéric Péters (fpeters) a relu et demandé des modifications sur une pull request sur Gitea concernant cette demande :
Updated by Robot Gitea about 1 month ago
- Status changed from En cours to Solution proposée
Benjamin Dauvergne (bdauvergne) a demandé une relecture de Frédéric Péters (fpeters) sur une pull request sur Gitea concernant cette demande :
Updated by Robot Gitea about 1 month ago
- Status changed from Solution proposée to Solution validée
Frédéric Péters (fpeters) a approuvé une pull request sur Gitea concernant cette demande :
Updated by Robot Gitea about 1 month ago
- Status changed from Solution validée to Résolu (à déployer)
Benjamin Dauvergne (bdauvergne) a mergé une pull request sur Gitea concernant cette demande :
- URL : https://git.entrouvert.org/entrouvert/wcs/pulls/1955
- Titre : améliorer les performances de /api/users/ et /api/users/xxx/ (#98514)
- Modifications : https://git.entrouvert.org/entrouvert/wcs/pulls/1955/files
Updated by Transition automatique about 1 month ago
- Status changed from Résolu (à déployer) to Solution déployée
misc: prefetch roles in user's api (#98514)