Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

N+1 Query in user_show_logs_json #750

Open
agdsn-sentry bot opened this issue Sep 18, 2024 · 1 comment
Open

N+1 Query in user_show_logs_json #750

agdsn-sentry bot opened this issue Sep 18, 2024 · 1 comment
Labels
enhancement 🔨 web/ui Things relating to Flask routes and Jinja templates

Comments

@agdsn-sentry
Copy link

agdsn-sentry bot commented Sep 18, 2024

Sentry Issue: PYCROFT-9C

Offending Spans db - SELECT "user".account_id AS user_account_i...
@agdsn-sentry agdsn-sentry bot added 🔨 web/ui Things relating to Flask routes and Jinja templates enhancement labels Sep 18, 2024
@lukasjuhrich
Copy link
Collaborator

lukasjuhrich commented Sep 18, 2024

These 6 lazy fetches cause ~300ms in the linked event. This is not negligible!

def user_show_logs_json(user_id: int, logtype: str = "all") -> ResponseReturnValue:
user = get_user_or_404(user_id)
if not is_log_type(logtype):
flash(f"{logtype!r} ist kein valider logtyp", "error")
abort(404)
logs = _iter_user_logs(user, logtype)
def sort_key(l: LogTableRow) -> int | None:
return l.created_at.timestamp
return TableResponse[LogTableRow](
items=sorted(logs, key=sort_key, reverse=True)
).model_dump()

def _iter_user_logs(user: User, logtype: LogType) -> t.Iterator[LogTableRow]:
if logtype in ["user", "all"]:
yield from (format_user_log_entry(e) for e in user.log_entries)
if logtype in ["room", "all"] and user.room:
yield from (format_room_log_entry(e) for e in user.room.log_entries)
if logtype in ["tasks", "all"]:
yield from (format_task_log_entry(e) for e in user.task_log_entries)
if logtype in ["hades", "all"]:
yield from formatted_user_hades_logs(user)

def format_log_entry(entry: LogEntry, log_type: LogType) -> LogTableRow:
return LogTableRow(
created_at=datetime_format(entry.created_at, formatter=datetime_filter),
user=UserColResponseNative(
title=entry.author.name,
href=url_for("user.user_show", user_id=entry.author.id),
),
message=Message.from_json(entry.message).localize(),
type=log_type,
)
format_user_log_entry = partial(format_log_entry, log_type='user')
format_task_log_entry = partial(format_log_entry, log_type='task')
format_room_log_entry = partial(format_log_entry, log_type='room')

It seems to me that these fetches come from entry.author, where entry is in user.log_entries, user.room.log_entries, user.task_log_entries.
We should try to

  • joinedload() the user.room
  • selectinload() the relevant logentries
  • joinedload() the logentries' author
    or something along these lines (measure!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement 🔨 web/ui Things relating to Flask routes and Jinja templates
Projects
None yet
Development

No branches or pull requests

1 participant