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:
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user