diff --git a/repositories/rules.go b/repositories/rules.go index 6b35fa8ba..e0971324f 100644 --- a/repositories/rules.go +++ b/repositories/rules.go @@ -48,9 +48,11 @@ func (repo *MarbleDbRepository) ListRulesByIterationId(ctx context.Context, exec ) } +// This method expects to be run in a transaction, because we set some local settings +// that should not be changed for the whole connection. func (repo *MarbleDbRepository) RulesExecutionStats( ctx context.Context, - exec Executor, + exec Transaction, organizationId string, iterationId string, begin, end time.Time, @@ -58,6 +60,17 @@ func (repo *MarbleDbRepository) RulesExecutionStats( if err := validateMarbleDbExecutor(exec); err != nil { return nil, err } + + // The following settings are set because in some cases at least, the query planner + // has ended up choosing a query plan involving a hash join with a full table scan on decision_rules + _, err := exec.Exec(ctx, + `SET local join_collapse_limit = 1; + SET local enable_hashjoin = off; + SET local enable_mergejoin = off;`) + if err != nil { + return nil, err + } + query := NewQueryBuilder(). Select("scir.stable_rule_id, scir.name, dr.outcome, scit.version, COUNT(*) as total"). From("decisions as d"). @@ -80,9 +93,11 @@ func (repo *MarbleDbRepository) RulesExecutionStats( ) } +// This method expects to be run in a transaction, because we set some local settings +// that should not be changed for the whole connection. func (repo *MarbleDbRepository) PhanomRulesExecutionStats( ctx context.Context, - exec Executor, + exec Transaction, organizationId string, iterationId string, begin, end time.Time, @@ -90,6 +105,17 @@ func (repo *MarbleDbRepository) PhanomRulesExecutionStats( if err := validateMarbleDbExecutor(exec); err != nil { return nil, err } + + // The following settings are set because in some cases at least, the query planner + // has ended up choosing a query plan involving a hash join with a full table scan on decision_rules + _, err := exec.Exec(ctx, + `SET local join_collapse_limit = 1; + SET local enable_hashjoin = off; + SET local enable_mergejoin = off;`) + if err != nil { + return nil, err + } + query := NewQueryBuilder(). Select("scir.stable_rule_id, scir.name, dr.outcome, scit.version, COUNT(*) as total"). From("phantom_decisions as d"). diff --git a/usecases/rules_usecase.go b/usecases/rules_usecase.go index fa7b0f116..673abd5b5 100644 --- a/usecases/rules_usecase.go +++ b/usecases/rules_usecase.go @@ -20,14 +20,14 @@ type RuleUsecaseRepository interface { ListRulesByIterationId(ctx context.Context, exec repositories.Executor, iterationId string) ([]models.Rule, error) RulesExecutionStats( ctx context.Context, - exec repositories.Executor, + exec repositories.Transaction, organizationId string, iterationId string, begin, end time.Time, ) ([]models.RuleExecutionStat, error) PhanomRulesExecutionStats( ctx context.Context, - exec repositories.Executor, + exec repositories.Transaction, organizationId string, iterationId string, begin, end time.Time, @@ -64,33 +64,38 @@ func (usecase *RuleUsecase) ListRules(ctx context.Context, iterationId string) ( } func (usecase *RuleUsecase) ListRuleExecution(ctx context.Context, testrunId string) ([]models.RuleExecutionStat, error) { - exec := usecase.executorFactory.NewExecutor() - testrun, err := usecase.scenarioTestRunRepository.GetTestRunByID(ctx, exec, testrunId) - if err != nil { - return nil, err - } - rules, err := usecase.repository.PhanomRulesExecutionStats( - ctx, - exec, - testrun.OrganizationId, - testrun.ScenarioIterationId, - testrun.CreatedAt, - testrun.ExpiresAt) - if err != nil { - return nil, err - } - liveRules, err := usecase.repository.RulesExecutionStats( - ctx, - exec, - testrun.OrganizationId, - testrun.ScenarioLiveIterationId, - testrun.CreatedAt, - testrun.ExpiresAt) - if err != nil { - return nil, err - } - result := append(rules, liveRules...) - return result, nil + var result []models.RuleExecutionStat + err := usecase.transactionFactory.Transaction(ctx, func(tx repositories.Transaction) error { + testrun, err := usecase.scenarioTestRunRepository.GetTestRunByID(ctx, tx, testrunId) + if err != nil { + return err + } + rules, err := usecase.repository.PhanomRulesExecutionStats( + ctx, + tx, + testrun.OrganizationId, + testrun.ScenarioIterationId, + testrun.CreatedAt, + testrun.ExpiresAt) + if err != nil { + return err + } + result = append(result, rules...) + + liveRules, err := usecase.repository.RulesExecutionStats( + ctx, + tx, + testrun.OrganizationId, + testrun.ScenarioLiveIterationId, + testrun.CreatedAt, + testrun.ExpiresAt) + if err != nil { + return err + } + result = append(result, liveRules...) + return nil + }) + return result, err } func (usecase *RuleUsecase) CreateRule(ctx context.Context, ruleInput models.CreateRuleInput) (models.Rule, error) {