Skip to content

Commit 782baba

Browse files
committed
feat: optimize GetAccount for large number of policies and rules
1 parent 7aef0f6 commit 782baba

File tree

1 file changed

+35
-13
lines changed

1 file changed

+35
-13
lines changed

management/server/store/sql_store.go

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -783,29 +783,53 @@ func (s *SqlStore) GetAccount(ctx context.Context, accountID string) (*types.Acc
783783
}()
784784

785785
var account types.Account
786+
// Do not use Preload(clause.Associations) as it will load all associations including those which don't work (e.g. Policy.Rules), leading to a double query
787+
// Also GroupPeers are not preloaded but loaded separately below
786788
result := s.db.Model(&account).
787-
Omit("GroupsG").
788-
Preload("UsersG.PATsG"). // have to be specifies as this is nester reference
789-
Preload(clause.Associations).
789+
Preload("Policies").
790+
Preload("SetupKeysG").
791+
Preload("PeersG").
792+
Preload("UsersG.PATsG").
793+
Preload("GroupsG").
794+
Preload("RoutesG").
795+
Preload("NameServerGroupsG").
796+
Preload("PostureChecks").
797+
Preload("Networks").
798+
Preload("NetworkRouters").
799+
Preload("NetworkResources").
800+
Preload("Onboarding").
790801
Take(&account, idQueryCondition, accountID)
802+
791803
if result.Error != nil {
792804
log.WithContext(ctx).Errorf("error when getting account %s from the store: %s", accountID, result.Error)
793805
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
794806
return nil, status.NewAccountNotFoundError(accountID)
795807
}
796808
return nil, status.NewGetAccountFromStoreError(result.Error)
797809
}
798-
799-
// we have to manually preload policy rules as it seems that gorm preloading doesn't do it for us
800-
for i, policy := range account.Policies {
801-
var rules []*types.PolicyRule
802-
err := s.db.Model(&types.PolicyRule{}).Find(&rules, "policy_id = ?", policy.ID).Error
803-
if err != nil {
810+
// we have to manually preload policy rules as it seems that gorm preloading does the query but does not use the results
811+
// with a high number of rules it is faster to do one query for all rules than one query per policy
812+
var policyIDs = make([]string, 0, len(account.Policies))
813+
for _, p := range account.Policies {
814+
policyIDs = append(policyIDs, p.ID)
815+
}
816+
if len(policyIDs) > 0 {
817+
var allRules []*types.PolicyRule
818+
if err := s.db.Model(&types.PolicyRule{}).Where("policy_id IN ?", policyIDs).Find(&allRules).Error; err != nil {
804819
return nil, status.Errorf(status.NotFound, "rule not found")
805820
}
806-
account.Policies[i].Rules = rules
821+
rulesByPolicyID := make(map[string][]*types.PolicyRule, len(account.Policies))
822+
for _, r := range allRules {
823+
rulesByPolicyID[r.PolicyID] = append(rulesByPolicyID[r.PolicyID], r)
824+
}
825+
for i := range account.Policies {
826+
rules, ok := rulesByPolicyID[account.Policies[i].ID]
827+
if !ok {
828+
return nil, status.Errorf(status.NotFound, "rule not found")
829+
}
830+
account.Policies[i].Rules = rules
831+
}
807832
}
808-
809833
account.SetupKeys = make(map[string]*types.SetupKey, len(account.SetupKeysG))
810834
for _, key := range account.SetupKeysG {
811835
account.SetupKeys[key.Key] = key.Copy()
@@ -827,13 +851,11 @@ func (s *SqlStore) GetAccount(ctx context.Context, accountID string) (*types.Acc
827851
account.Users[user.Id] = user.Copy()
828852
}
829853
account.UsersG = nil
830-
831854
account.Groups = make(map[string]*types.Group, len(account.GroupsG))
832855
for _, group := range account.GroupsG {
833856
account.Groups[group.ID] = group.Copy()
834857
}
835858
account.GroupsG = nil
836-
837859
var groupPeers []types.GroupPeer
838860
s.db.Model(&types.GroupPeer{}).Where("account_id = ?", accountID).
839861
Find(&groupPeers)

0 commit comments

Comments
 (0)