Folders: Reduce DB queries when counting and deleting resources under folders (#81153)

* Add folder store method for fetching all folder descendants

* Modify GetDescendantCounts() to fetch folder descendants at once

* Reduce DB calls when counting library panels under dashboard

* Reduce DB calls when counting dashboards under folder

* Reduce DB calls during folder delete

* Modify folder registry to count/delete entities under multiple folders

* Reduce DB calls when counting

* Reduce DB calls when deleting
This commit is contained in:
Sofia Papagiannaki
2024-01-30 18:26:34 +02:00
committed by GitHub
parent 0139ac205d
commit 89d3b55bec
24 changed files with 335 additions and 411 deletions
+47 -25
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"strings"
"time"
"xorm.io/xorm"
@@ -657,7 +658,12 @@ func (d *dashboardStore) DeleteDashboard(ctx context.Context, cmd *dashboards.De
}
func (d *dashboardStore) deleteDashboard(cmd *dashboards.DeleteDashboardCommand, sess *db.Session, emitEntityEvent bool) error {
dashboard := dashboards.Dashboard{ID: cmd.ID, OrgID: cmd.OrgID}
dashboard := dashboards.Dashboard{OrgID: cmd.OrgID}
if cmd.UID != "" {
dashboard.UID = cmd.UID
} else {
dashboard.ID = cmd.ID
}
has, err := sess.Get(&dashboard)
if err != nil {
return err
@@ -1008,42 +1014,58 @@ func (d *dashboardStore) GetDashboardTags(ctx context.Context, query *dashboards
// CountDashboardsInFolder returns a count of all dashboards associated with the
// given parent folder ID.
//
// This will be updated to take CountDashboardsInFolderQuery as an argument and
// lookup dashboards using the ParentFolderUID when dashboards are associated with a parent folder UID instead of ID.
func (d *dashboardStore) CountDashboardsInFolder(
func (d *dashboardStore) CountDashboardsInFolders(
ctx context.Context, req *dashboards.CountDashboardsInFolderRequest) (int64, error) {
if len(req.FolderUIDs) == 0 {
return 0, nil
}
var count int64
var err error
err = d.store.WithDbSession(ctx, func(sess *db.Session) error {
err := d.store.WithDbSession(ctx, func(sess *db.Session) error {
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc()
// nolint:staticcheck
session := sess.In("folder_id", req.FolderID).In("org_id", req.OrgID).
In("is_folder", d.store.GetDialect().BooleanStr(false))
count, err = session.Count(&dashboards.Dashboard{})
s := strings.Builder{}
args := make([]any, 0, 3)
s.WriteString("SELECT COUNT(*) FROM dashboard WHERE ")
if len(req.FolderUIDs) == 1 && req.FolderUIDs[0] == "" {
s.WriteString("folder_uid IS NULL")
} else {
s.WriteString(fmt.Sprintf("folder_uid IN (%s)", strings.Repeat("?,", len(req.FolderUIDs)-1)+"?"))
for _, folderUID := range req.FolderUIDs {
args = append(args, folderUID)
}
}
s.WriteString(" AND org_id = ? AND is_folder = ?")
args = append(args, req.OrgID, d.store.GetDialect().BooleanStr(false))
sql := s.String()
_, err := sess.SQL(sql, args...).Get(&count)
return err
})
return count, err
}
func (d *dashboardStore) DeleteDashboardsInFolder(
func (d *dashboardStore) DeleteDashboardsInFolders(
ctx context.Context, req *dashboards.DeleteDashboardsInFolderRequest) error {
return d.store.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
dashboard := dashboards.Dashboard{OrgID: req.OrgID}
has, err := sess.Where("uid = ? AND org_id = ?", req.FolderUID, req.OrgID).Get(&dashboard)
if err != nil {
return err
}
if !has {
return dashboards.ErrFolderNotFound
}
// TODO delete all dashboards in the folder in a bulk query
for _, folderUID := range req.FolderUIDs {
dashboard := dashboards.Dashboard{OrgID: req.OrgID}
has, err := sess.Where("org_id = ? AND uid = ?", req.OrgID, folderUID).Get(&dashboard)
if err != nil {
return err
}
if !has {
return dashboards.ErrFolderNotFound
}
if err := d.deleteChildrenDashboardAssociations(sess, &dashboard); err != nil {
return err
}
if err := d.deleteChildrenDashboardAssociations(sess, &dashboard); err != nil {
return err
}
_, err = sess.Where("folder_id = ? AND org_id = ? AND is_folder = ?", dashboard.ID, dashboard.OrgID, false).Delete(&dashboards.Dashboard{})
return err
_, err = sess.Where("folder_id = ? AND org_id = ? AND is_folder = ?", dashboard.ID, dashboard.OrgID, false).Delete(&dashboards.Dashboard{})
if err != nil {
return err
}
}
return nil
})
}