Project

General

Profile

Développement #98514

/api/users/: problème de requêtes N+1 sur les rôles

Added by Benjamin Dauvergne 2 months ago. Updated about 1 month ago.

Status:
Solution déployée
Priority:
Normal
Target version:
-
Start date:
14 November 2024
Due date:
% Done:

0%

Estimated time:
Patch proposed:
No
Planning:
No

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

Revision 9996f74e (diff)
Added by Benjamin Dauvergne about 1 month ago

misc: prefetch roles in user's api (#98514)

Revision d4665a80 (diff)
Added by Benjamin Dauvergne about 1 month ago

misc: move template constructor out of loop (#98514)

Revision c5a0a1b7 (diff)
Added by Benjamin Dauvergne about 1 month ago

misc: prefetch roles in user datasources (#98514)

History

#1

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.

#2

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 :

#3

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.

#4

Updated by Robot Gitea 2 months ago

  • Status changed from En cours to Solution proposée
#5

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 :

#6

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 :

#7

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 :

#8

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 :

#9

Updated by Transition automatique about 1 month ago

  • Status changed from Résolu (à déployer) to Solution déployée

Also available in: Atom PDF