1
0

feat(subscription): use a recursive cte to fetch subscriptions of parent projects

Testing this locally resulted in improved response times from ~50ms to ~20ms when creating a project. It looks like even though the code running these sql queries uses different go routines, they affect each other (caused by IO or context switching?)
This commit is contained in:
kolaente 2024-03-03 15:31:42 +01:00
parent 22933dac4a
commit fe27dd59ad
No known key found for this signature in database
GPG Key ID: F40E70337AB24C9B
2 changed files with 26 additions and 43 deletions

View File

@ -540,19 +540,24 @@ func getSavedFilterProjects(s *xorm.Session, doer *user.User) (savedFiltersProje
} }
// GetAllParentProjects returns all parents of a given project // GetAllParentProjects returns all parents of a given project
func (p *Project) GetAllParentProjects(s *xorm.Session) (err error) { func GetAllParentProjects(s *xorm.Session, projectID int64) (allProjects map[int64]*Project, err error) {
if p.ParentProjectID == 0 { allProjects = make(map[int64]*Project)
return err = s.SQL(`WITH RECURSIVE all_projects AS (
} SELECT
p.*
parent, err := GetProjectSimpleByID(s, p.ParentProjectID) FROM
if err != nil { projects p
return err WHERE
} p.id = ?
UNION ALL
p.ParentProject = parent SELECT
p.*
return parent.GetAllParentProjects(s) FROM
projects p
INNER JOIN all_projects pc ON p.ID = pc.parent_project_id
)
SELECT DISTINCT * FROM all_projects`, projectID).Find(&allProjects)
return
} }
// addProjectDetails adds owner user objects and project tasks to all projects in the slice // addProjectDetails adds owner user objects and project tasks to all projects in the slice
@ -667,29 +672,9 @@ func checkProjectBeforeUpdateOrDelete(s *xorm.Session, project *Project) (err er
} }
} }
allProjects := make(map[int64]*Project) allProjects, err := GetAllParentProjects(s, project.ParentProjectID)
err = s.SQL(`WITH RECURSIVE all_projects AS (
SELECT
p.id,
p.parent_project_id
FROM
projects p
WHERE
p.id = ?
UNION ALL
SELECT
p.id,
p.parent_project_id
FROM
projects p
INNER JOIN all_projects pc ON p.ID = pc.parent_project_id
)
SELECT
*
FROM
all_projects`, project.ParentProjectID).Find(&allProjects)
if err != nil { if err != nil {
return return err
} }
var parent *Project var parent *Project

View File

@ -301,20 +301,18 @@ func GetSubscriptionsForProjects(s *xorm.Session, projects []*Project, a web.Aut
continue continue
} }
err = ps[p.ID].GetAllParentProjects(s) parents, err := GetAllParentProjects(s, p.ID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
parentIDs := []int64{} // Walk the tree up until we reach the top
var parent = ps[p.ID].ParentProject var parent = parents[p.ParentProjectID] // parent now has a pointer…
ps[p.ID].ParentProject = parents[p.ParentProjectID]
for parent != nil { for parent != nil {
parentIDs = append(parentIDs, parent.ID) allProjectIDs = append(allProjectIDs, parent.ID)
parent = parent.ParentProject parent = parents[parent.ParentProjectID] // … which means we can update it here and then update the pointer in the map
} }
// Now we have all parent ids
allProjectIDs = append(allProjectIDs, parentIDs...) // the child project id is already in there
} }
var subscriptions []*Subscription var subscriptions []*Subscription