From 84b05313c1ca854adabbff1b6813354b204c7030 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Mon, 28 Oct 2024 15:46:55 +0100 Subject: [PATCH] Fix very slow workflow editor loading Loading the editor for my usegalaxy.org account takes 20 seconds. I've narrowed this down to the unnecessary join against the workflow table and loading all steps. I'm also returning the needed columns directly. --- .../webapps/galaxy/controllers/workflow.py | 54 +++++++++++++------ 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/controllers/workflow.py b/lib/galaxy/webapps/galaxy/controllers/workflow.py index 085834f67ec0..5928e925df58 100644 --- a/lib/galaxy/webapps/galaxy/controllers/workflow.py +++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py @@ -1,8 +1,13 @@ import logging from markupsafe import escape -from sqlalchemy import desc -from sqlalchemy.orm import joinedload +from sqlalchemy import ( + and_, + desc, + false, + func, + select, +) from galaxy import ( model, @@ -166,13 +171,32 @@ def editor(self, trans, id=None, workflow_id=None, version=None, **kwargs): # The following query loads all user-owned workflows, # So that they can be copied or inserted in the workflow editor. - workflows = ( - trans.sa_session.query(model.StoredWorkflow) - .filter_by(user=trans.user, deleted=False, hidden=False) - .order_by(desc(model.StoredWorkflow.table.c.update_time)) - .options(joinedload(model.StoredWorkflow.latest_workflow).joinedload(model.Workflow.steps)) - .all() + assert trans.user # help out type checker, require_login means we will have a user + workflow_stmnt = ( + select( + model.StoredWorkflow.id, + model.StoredWorkflow.latest_workflow_id, + model.StoredWorkflow.name, + func.coalesce(func.count(model.WorkflowStep.id), 0).label("step_count"), + ) + .join( + model.WorkflowStep, + model.StoredWorkflow.latest_workflow_id == model.WorkflowStep.workflow_id, + isouter=True, + ) + .where( + and_( + model.StoredWorkflow.user_id == trans.user.id, + model.StoredWorkflow.deleted == false(), + model.StoredWorkflow.hidden == false(), + ) + ) + .group_by( + model.StoredWorkflow.id, + ) + .order_by(desc(model.StoredWorkflow.update_time)) ) + workflow_results = trans.sa_session.execute(workflow_stmnt).all() # create workflow module models module_sections = [] @@ -219,13 +243,13 @@ def editor(self, trans, id=None, workflow_id=None, version=None, **kwargs): # create workflow models workflows = [ { - "id": trans.security.encode_id(workflow.id), - "latest_id": trans.security.encode_id(workflow.latest_workflow.id), - "step_count": len(workflow.latest_workflow.steps), - "name": workflow.name, + "id": trans.security.encode_id(stored_workflow_id), + "latest_id": trans.security.encode_id(latest_workflow_id), + "step_count": step_count, + "name": workflow_name, } - for workflow in workflows - if new_workflow or workflow.id != stored.id + for stored_workflow_id, latest_workflow_id, workflow_name, step_count in workflow_results + if not stored or stored_workflow_id != stored.id ] # build workflow editor model @@ -236,7 +260,7 @@ def editor(self, trans, id=None, workflow_id=None, version=None, **kwargs): } # for existing workflow add its data to the model - if new_workflow is False: + if stored: editor_config.update( { "id": trans.security.encode_id(stored.id),